*
* Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.
*
* Description: show help information of cm_ctl
*
* Filename: /cm_ctl/ctl_param_check.cpp
*
* -------------------------------------------------------------------------
*/
#include <cmath>
#include <cstdlib>
#include "securec.h"
#include "cm_misc.h"
#include "securec_check.h"
#include "cm/libpq-fe.h"
#include "ctl_common.h"
#include "cjson/cJSON.h"
const char *g_cmaParamInfo[] = {
"log_dir|string|0,0|NULL|NULL|",
"log_file_size|int|0,2047|MB|NULL|",
"log_min_messages|enum|debug5,debug1,log,warning,error,fatal|NULL|NULL|",
"incremental_build|bool|0,0|NULL|NULL|",
"security_mode|bool|0,0|NULL|NULL|",
"upgrade_from|int|0,4294967295|NULL|For upgrading, specify which version we are upgrading from.|",
"alarm_component|string|0,0|NULL|NULL|",
"agent_report_interval|int|0,2147483647|NULL|NULL|",
"agent_heartbeat_timeout|int|2,2147483647|NULL|NULL|",
"agent_connect_timeout|int|0,2147483647|NULL|NULL|",
"agent_connect_retries|int|0,2147483647|NULL|NULL|",
"agent_kill_instance_timeout|int|0,2147483647|NULL|NULL|",
"alarm_report_interval|int|0,2147483647|NULL|NULL|",
"alarm_report_max_count|int|1,2592000|NULL|NULL|",
"agent_check_interval|int|0,2147483647|NULL|NULL|",
"diskusage_threshold_value_check|int|0,100|NULL|NULL|",
"disk_check_timeout|int|0,2147483647|NULL|NULL|",
"disk_check_interval|int|0,2147483647|NULL|NULL|",
"disk_check_buffer_size|int|0,2147483647|NULL|NULL|",
"enable_xalarmd_slow_disk_check|bool|0,0|NULL|NULL|",
"enable_xalarm_event_check|bool|0,0|NULL|NULL|",
"xalarm_node_map|string|0,0|NULL|NULL|",
"enable_log_compress|bool|0,0|NULL|NULL|",
"enable_vtable|bool|0,0|NULL|NULL|",
"enable_ssl|bool|0,0|NULL|NULL|",
"ssl_cert_expire_alert_threshold|int|7,180|NULL|NULL|",
"ssl_cert_expire_check_interval|int|0,2147483647|NULL|NULL|",
"process_cpu_affinity|int|0,2|NULL|Only the ARM architecture is supported.|",
"enable_xc_maintenance_mode|bool|0,0|NULL|NULL|",
"log_threshold_check_interval|int|0,2147483647|NULL|NULL|",
"log_max_size|int|0,2147483647|NULL|NULL|",
"log_max_count|int|0,30000|NULL|NULL|",
"log_saved_days|int|0,1000|NULL|NULL|",
"agent_phony_dead_check_interval|int|0,2147483647|NULL|NULL|",
"unix_socket_directory|string|0,0|NULL|NULL|",
"dilatation_shard_count_for_disk_capacity_alarm|int|0,2147483647|NULL|NULL|",
"enable_dcf|bool|0,0|NULL|NULL|",
"disaster_recovery_type|int|0,2|NULL|NULL|",
"agent_backup_open|int|0,2|NULL|NULL|",
"enable_e2e_rto|int|0,1|NULL|NULL|",
"disk_timeout|int|0,2147483647|NULL|NULL|",
"voting_disk_path|string|0,0|NULL|NULL|",
"agent_rhb_interval|int|0,2147483647|NULL|NULL|",
#ifndef ENABLE_MULTIPLE_NODES
"enable_fence_dn|bool|0,0|NULL|NULL|",
#else
"enable_cn_auto_repair|bool|0,0|NULL|NULL|",
"enable_gtm_phony_dead_check|int|0,1|NULL|NULL|",
#endif
"environment_threshold|string|0,0|NULL|NULL|",
"db_service_vip|string|0,0|NULL|NULL|",
"event_triggers|string|0,0|NULL|NULL|",
"ss_double_cluster_mode|int|0,2|NULL|NULL|",
};
const char *g_cmsParamInfo[] = {
"log_dir|string|0,0|NULL|NULL|",
"log_file_size|int|0,2047|MB|NULL|",
"log_min_messages|enum|debug5,debug1,log,warning,error,fatal|NULL|NULL|",
"thread_count|int|2,1000|NULL|NULL|",
"instance_heartbeat_timeout|int|1,2147483647|NULL|NULL|",
"instance_failover_delay_timeout|int|0,2147483647|NULL|NULL|",
"cmserver_ha_connect_timeout|int|0,2147483647|NULL|NULL|",
"cmserver_ha_heartbeat_timeout|int|1,2147483647|NULL|NULL|",
"cmserver_ha_status_interval|int|1,2147483647|NULL|NULL|",
"cmserver_self_vote_timeout|int|0,2147483647|NULL|NULL|",
"phony_dead_effective_time|int|1,2147483647|NULL|NULL|",
"cm_server_arbitrate_delay_base_time_out|int|0,2147483647|NULL|NULL|",
"cm_server_arbitrate_delay_incrememtal_time_out|int|0,2147483647|NULL|NULL|",
"alarm_component|string|0,0|NULL|NULL|",
"alarm_report_interval|int|0,2147483647|NULL|NULL|",
"alarm_report_max_count|int|1,2592000|NULL|NULL|",
"instance_keep_heartbeat_timeout|int|0,2147483647|NULL|NULL|",
"az_switchover_threshold|int|1,100|NULL|NULL|",
"az_check_and_arbitrate_interval|int|1,2147483647|NULL|NULL|",
"az_connect_check_interval|int|1,2147483647|NULL|NULL|",
"az_connect_check_delay_time|int|1,2147483647|NULL|NULL|",
"cmserver_demote_delay_on_etcd_fault|int|1,2147483647|NULL|NULL|",
"instance_phony_dead_restart_interval|int|0,2147483647|NULL|NULL|",
"enable_transaction_read_only|bool|0,0|NULL|NULL|",
"datastorage_threshold_check_interval|int|1,2592000|NULL|NULL|",
"datastorage_threshold_value_check|int|1,99|NULL|NULL|",
"ss_enable_check_sys_disk_usage|bool|0,0|NULL|NULL|",
"max_datastorage_threshold_check|int|1,2592000|NULL|NULL|",
"enable_az_auto_switchover|int|0,1|NULL|NULL|",
"cm_auth_method|enum|trust,gss|NULL|NULL|",
"cm_krb_server_keyfile|string|0,0|NULL|NULL|",
"switch_rto|int|60,2147483647|NULL|NULL|",
"force_promote|int|0,1|NULL|NULL|",
"backup_open|int|0,2|NULL|NULL|",
"enable_dcf|bool|0,0|NULL|NULL|",
"ddb_type|int|0,2|NULL|NULL|",
"enable_ssl|bool|0,0|NULL|NULL|",
"ssl_cert_expire_alert_threshold|int|7,180|NULL|NULL|",
"ssl_cert_expire_check_interval|int|0,2147483647|NULL|NULL|",
"delay_arbitrate_timeout|int|0,2147483647|NULL|NULL|",
"delay_arbitrate_max_cluster_timeout|int|0,1000|NULL|NULL|",
"ddb_log_level|string|0,0|NULL|NULL|",
"ddb_log_backup_file_count|int|1,100|NULL|NULL|",
"ddb_max_log_file_size|string|0,0|NULL|NULL|",
"ddb_log_suppress_enable|int|0,1|NULL|NULL|",
"ddb_election_timeout|int|1,600|NULL|NULL|",
"enable_e2e_rto|int|0,1|NULL|NULL|",
"disk_timeout|int|0,2147483647|NULL|NULL|",
"agent_network_timeout|int|0,2147483647|NULL|NULL|",
"share_disk_path|string|0,0|NULL|NULL|",
"voting_disk_path|string|0,0|NULL|NULL|",
"dn_arbitrate_mode|enum|quorum,paxos,share_disk|NULL|NULL|",
"agent_fault_timeout|int|0,2147483647|NULL|NULL|",
#ifdef ENABLE_MULTIPLE_NODES
"coordinator_heartbeat_timeout|int|0,2592000|NULL|if set 0,the function is disabled|",
"cluster_starting_aribt_delay|int|1,2592000|NULL|NULL|",
#endif
"third_party_gateway_ip|string|0,0|NULL|NULL|",
"cms_enable_failover_on2nodes|bool|0,0|NULL|NULL|",
"cms_enable_db_crash_recovery|bool|0,0|NULL|NULL|",
"cms_network_isolation_timeout|int|10,2147483647|NULL|NULL|",
"enable_set_most_available_sync|bool|0,0|NULL|NULL|",
"cmserver_set_most_available_sync_delay_times|int|0,2147483647|NULL|NULL|",
#ifndef ENABLE_PRIVATEGAUSS
"wait_static_primary_times|int|5,2147483647|NULL|NULL|",
#endif
"ss_double_cluster_mode|int|0,2|NULL|NULL|",
"share_disk_lock_type|int|0,1|NULL|NULL|",
"upgrade_from|int|0,4294967295|NULL|For upgrading, specify which version we are upgrading from.|",
"cms_enable_failover_cascade|bool|0,0|NULL|NULL|",
};
const char *g_valueTypeStr[] = {
"bool",
"enum",
"integer",
"string",
};
const char *g_boolValueList[] = {
"true",
"false",
"on",
"off",
"yes",
"no",
"0",
"1",
"y",
"n",
"t",
"f",
};
const char *g_ddbLogLevelList[] {
"RUN_ERR",
"RUN_WAR",
"RUN_INF",
"DEBUG_ERR",
"DEBUG_WAR",
"DEBUG_INF",
"TRACE",
"PROFILE",
"OPER"
};
using UnitType = enum UnitTypeEn {
UNIT_ERROR = -1,
UNIT_KB,
UNIT_MB,
UNIT_GB,
UNIT_MS,
UNIT_S,
UNIT_MIN,
UNIT_H,
UNIT_D
};
using CmParaType = enum CmParaTypeEn {
CM_PARA_ERROR = -1,
CM_PARA_BOOL,
CM_PARA_ENUM,
CM_PARA_INT,
CM_PARA_STRING
};
using ParamEnumEntry = struct ParamEnumEntrySt {
CmParaType type;
char name[MAX_PATH_LEN];
char value[MAX_PATH_LEN];
char unit[MAX_PATH_LEN];
char message[MAX_PATH_LEN];
};
using ParamMinMaxValue = struct ParamMinMaxValueSt {
char minValStr[MAX_PATH_LEN];
char maxValStr[MAX_PATH_LEN];
};
static const int UNIT_BITNESS = 2;
static const int DECIMAL_NOTATION = 10;
static const int MAX_DDB_LOG_FILE_SIZE = 1000;
static const int THRESHOLD_FORMAT = 4;
static const int THRESHOLD_MAX_VALUE = 100;
static const int THRESHOLD_MIN_VALUE = 0;
using EventTriggerType = enum EventTriggerTypeEn {
EVENT_UNKNOWN = -1,
EVENT_START = 0,
EVENT_STOP,
EVENT_FAILOVER,
EVENT_SWITCHOVER,
EVENT_COUNT
};
typedef struct TriggerTypeStringMap {
EventTriggerType type;
char *typeStr;
} TriggerTypeStringMap;
const TriggerTypeStringMap triggerTypeStringMap[EVENT_COUNT] = {
{EVENT_START, "on_start"},
{EVENT_STOP, "on_stop"},
{EVENT_FAILOVER, "on_failover"},
{EVENT_SWITCHOVER, "on_switchover"}
};
static status_t CheckEventTriggers(const char *value);
static status_t CheckParameterNameType(const char *param)
{
if (param == NULL) {
write_runlog(ERROR, "The parameter is NULL.\n");
return CM_ERROR;
}
int paramLen = (int)strnlen(param, MAX_PATH_LEN);
if (param[0] == '_' || param[paramLen - 1] == '_') {
write_runlog(ERROR, "The param(%s) start or end with illegal character '_'.\n", param);
return CM_ERROR;
}
for (int i = 0; i < paramLen; ++i) {
if (!isalpha((unsigned char)(param[i])) && !isdigit((unsigned char)(param[i])) && (param[i] != '_')) {
write_runlog(ERROR, "The param(%s) exists illegal character:%c.\n", param, param[i]);
return CM_ERROR;
}
}
return CM_SUCCESS;
}
static status_t CheckParameterValueType(const char *value)
{
int count = 0;
if (value == NULL) {
write_runlog(ERROR, "The value is NULL.\n");
return CM_ERROR;
}
if ((!isdigit((unsigned char)(value[0]))) && (value[0] != '\'') && (value[0] != '(') &&
(!isalpha((unsigned char)(value[0]))) && (value[0] != '-') && (value[0] != ')') && (value[0] != '{')) {
write_runlog(ERROR, "The parameter value(%s) exists illegal character:\"%c\".\n", value, value[0]);
return CM_ERROR;
}
for (int i = 0; i < (int)strnlen(value, MAX_PATH_LEN); ++i) {
if (value[i] == '\'') {
++count;
}
if (value[i] == '#') {
write_runlog(ERROR, "The parameter value(%s) exists illegal character:\"%c\".\n", value, value[i]);
return CM_ERROR;
}
}
if (count == 1) {
write_runlog(ERROR, "%s: the character '\'' can not make a pair or to many.\n", value);
return CM_ERROR;
}
return CM_SUCCESS;
}
static void MakeStrTolower(const char *source, char *dest, const int destLen)
{
int len = (int)strlen(source);
if (len > destLen) {
len = destLen;
}
for (int i = 0; i < len; i++) {
dest[i] = (char)tolower(source[i]);
}
dest[len] = '\0';
}
char *GetParamLineInfo(const char *paramName, const char * const *paramInfos, int paramInfosLen)
{
int ret;
char *info;
char tmpParaName[MAX_PATH_LEN] = {0};
char newParaName[MAX_PATH_LEN] = {0};
info = (char*)malloc(MAX_PATH_LEN * sizeof(char));
if (info == NULL) {
write_runlog(ERROR, "Out of memory: GetParamLineInfo.\n");
return NULL;
}
ret = memset_s(info, (MAX_PATH_LEN * sizeof(char)), 0, (MAX_PATH_LEN * sizeof(char)));
securec_check_errno(ret, (void)ret);
if (paramInfos == NULL) {
write_runlog(ERROR, "Fail to get param info.\n");
free(info);
return NULL;
}
for (int i = 0; i < paramInfosLen; ++i) {
MakeStrTolower(paramName, tmpParaName, sizeof(tmpParaName));
ret = snprintf_s(newParaName, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s|", tmpParaName);
securec_check_intval(ret, (void)ret);
if (strncmp(paramInfos[i], newParaName, strnlen(newParaName, MAX_PATH_LEN)) != 0) {
continue;
}
ret = snprintf_s(info, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s", paramInfos[i]);
securec_check_intval(ret, (void)ret);
return info;
}
return NULL;
}
static char *GetOneParamInfo(const GucOption &gucCtx)
{
if (gucCtx.nodeType == NODE_TYPE_AGENT) {
return GetParamLineInfo(gucCtx.parameter, g_cmaParamInfo, (int)lengthof(g_cmaParamInfo));
}
if (gucCtx.nodeType == NODE_TYPE_SERVER) {
return GetParamLineInfo(gucCtx.parameter, g_cmsParamInfo, (int)lengthof(g_cmsParamInfo));
}
write_runlog(ERROR, "unrecognized -Z parameter.\n");
return NULL;
}
static CmParaType GetParamType(const char *type)
{
if (strncmp(type, "bool", strlen("bool")) == 0) {
return CM_PARA_BOOL;
}
if (strncmp(type, "int", strlen("int")) == 0) {
return CM_PARA_INT;
}
if (strncmp(type, "enum", strlen("enum")) == 0) {
return CM_PARA_ENUM;
}
if (strncmp(type, "string", strlen("string")) == 0) {
return CM_PARA_STRING;
}
return CM_PARA_ERROR;
}
static status_t GetConfigParamType(const char *ptr, ParamEnumEntry &varList)
{
if (ptr != NULL) {
CmParaType paramType = GetParamType(ptr);
if (paramType == CM_PARA_ERROR) {
write_runlog(DEBUG1, "Failed to parse \"%s\" info. The type \"%s\" is incorrect.\n", varList.name, ptr);
return CM_ERROR;
}
varList.type = paramType;
}
return CM_SUCCESS;
}
static status_t GetConfigParamValue(const char *ptr, ParamEnumEntry &varList)
{
int ret;
if (ptr == NULL) {
write_runlog(DEBUG1, "Failed to parse the \"%s\" info. The value is null.\n", varList.name);
return CM_ERROR;
}
ret = snprintf_s(varList.value, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s", ptr);
securec_check_intval(ret, (void)ret);
return CM_SUCCESS;
}
static status_t GetConfigParamUnit(const char *ptr, ParamEnumEntry &varList)
{
int ret;
if (ptr == NULL) {
write_runlog(DEBUG1, "Failed to parse the \"%s\" info. The parameter unit is incorrect.\n", varList.name);
return CM_ERROR;
}
if (strncmp(ptr, "NULL", strlen("NULL")) == 0) {
ret = memset_s(varList.unit, MAX_PATH_LEN, 0, MAX_PATH_LEN);
securec_check_errno(ret, (void)ret);
} else {
ret = snprintf_s(varList.unit, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s", ptr);
securec_check_intval(ret, (void)ret);
}
return CM_SUCCESS;
}
static status_t GetConfigParamMessage(const char *ptr, ParamEnumEntry &varList)
{
int ret;
if (ptr == NULL) {
write_runlog(DEBUG1, "Failed to parse \"%s\" info. The param relation message is incorrect.\n", varList.name);
return CM_ERROR;
}
if (strncmp(ptr, "NULL", strlen("NULL")) == 0) {
ret = memset_s(varList.message, MAX_PATH_LEN, 0, MAX_PATH_LEN);
securec_check_errno(ret, (void)ret);
} else {
ret = snprintf_s(varList.message, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s", ptr);
securec_check_intval(ret, (void)ret);
}
return CM_SUCCESS;
}
static status_t ParseParamInfo(const char *infoStr, ParamEnumEntry &varList)
{
int ret;
char* ptr;
char* buf = NULL;
const char *delim = "|";
char info[MAX_PATH_LEN] = {0};
ret = snprintf_s(info, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s", infoStr);
securec_check_intval(ret, (void)ret);
ptr = strtok_r(info, delim, &buf);
if (ptr != NULL) {
ret = snprintf_s(varList.name, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s", ptr);
securec_check_intval(ret, (void)ret);
}
ptr = strtok_r(NULL, delim, &buf);
if (GetConfigParamType(ptr, varList) != CM_SUCCESS) {
return CM_ERROR;
}
ptr = strtok_r(NULL, delim, &buf);
if (GetConfigParamValue(ptr, varList) != CM_SUCCESS) {
return CM_ERROR;
}
ptr = strtok_r(NULL, delim, &buf);
if (GetConfigParamUnit(ptr, varList) != CM_SUCCESS) {
return CM_ERROR;
}
ptr = strtok_r(NULL, delim, &buf);
if (GetConfigParamMessage(ptr, varList) != CM_SUCCESS) {
return CM_ERROR;
}
ptr = strtok_r(NULL, delim, &buf);
if (ptr != NULL && ptr[0] != '\n') {
write_runlog(DEBUG1, "The param \"%s\" conf info is incorrect.\n", varList.name);
return CM_ERROR;
}
return CM_SUCCESS;
}
static bool IsValueInRange(const char *listValue, const char *value)
{
int ret;
char *ptr;
char *buf = NULL;
char confParamVal[MAX_PATH_LEN] = {0};
const char *delim = ",";
ret = snprintf_s(confParamVal, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s", listValue);
securec_check_intval(ret, (void)ret);
ptr = strtok_r(confParamVal, delim, &buf);
while (ptr != NULL) {
if (strcmp(ptr, value) == 0) {
return true;
}
ptr = strtok_r(NULL, delim, &buf);
}
return false;
}
static status_t CheckBoolTypeValue(const char *param, const char *value)
{
uint32 listNums = lengthof(g_boolValueList);
if (IsStringInList(value, g_boolValueList, listNums)) {
return CM_SUCCESS;
}
write_runlog(ERROR, "The value \"%s\" is outside the valid range(on|off|yes|no|true|false|1|0) for parameter "
"\"%s\".\n", value, param);
return CM_ERROR;
}
static status_t CheckEnumTypeValue(const char *param, const char *value, const char *listValue)
{
char *buf = NULL;
char *tmpPtr = NULL;
char *valuePtr = NULL;
const char *delim = ",";
char tmpValue[MAX_PATH_LEN] = {0};
if (listValue == NULL || listValue[0] == '\0') {
write_runlog(ERROR, "Failed to obtain the range information of parameter \"%s\".\n", param);
return CM_ERROR;
}
MakeStrTolower(value, tmpValue, sizeof(tmpValue));
if (strlen(tmpValue) > 0) {
valuePtr = strtok_r(tmpValue, delim, &buf);
} else {
write_runlog(ERROR, "Unrecognized the value \"%s\".\n", value);
return CM_ERROR;
}
while (valuePtr != NULL) {
tmpPtr = valuePtr;
while (isspace((unsigned char)*tmpPtr)) {
tmpPtr++;
}
if (IsValueInRange(listValue, tmpPtr)) {
valuePtr = strtok_r(NULL, delim, &buf);
} else {
write_runlog(ERROR, "The value \"%s\" is outside the valid range(%s) for parameter \"%s\".\n",
value, listValue, param);
return CM_ERROR;
}
}
return CM_SUCCESS;
}
UnitType GetParamUnit(const char *unit)
{
if (strncmp(unit, "KB", strlen("KB")) == 0) {
return UNIT_KB;
}
if (strncmp(unit, "MB", strlen("MB")) == 0) {
return UNIT_MB;
}
if (strncmp(unit, "GB", strlen("GB")) == 0) {
return UNIT_GB;
}
if (strncmp(unit, "ms", strlen("ms")) == 0) {
return UNIT_MS;
}
if (strncmp(unit, "s", strlen("s")) == 0) {
return UNIT_S;
}
if (strncmp(unit, "min", strlen("min")) == 0) {
return UNIT_MIN;
}
if (strncmp(unit, "h", strlen("h")) == 0) {
return UNIT_H;
}
if (strncmp(unit, "d", strlen("d")) == 0) {
return UNIT_D;
}
return UNIT_ERROR;
}
static status_t ProcessMemUnit(const UnitType &unit, char *&endPtr, const char *param)
{
if (unit == UNIT_KB) {
if (strncmp(endPtr, "KB", UNIT_BITNESS) != 0) {
write_runlog(ERROR, "Valid units for this parameter \"%s\" is \"KB\".\n", param);
return CM_ERROR;
}
endPtr += UNIT_BITNESS;
}
if (unit == UNIT_MB) {
if (strncmp(endPtr, "MB", UNIT_BITNESS) != 0) {
write_runlog(ERROR, "Valid units for this parameter \"%s\" is, \"MB\".\n", param);
return CM_ERROR;
}
endPtr += UNIT_BITNESS;
}
if (unit == UNIT_GB) {
if (strncmp(endPtr, "GB", UNIT_BITNESS) != 0) {
write_runlog(ERROR, "Valid units for this parameter \"%s\" is \"GB\".\n", param);
return CM_ERROR;
}
endPtr += UNIT_BITNESS;
}
return CM_SUCCESS;
}
static status_t ProcessTimeUnit(const UnitType &unit, char *&endPtr, const char *param)
{
if (unit == UNIT_MS) {
if (strncmp(endPtr, "ms", UNIT_BITNESS) != 0) {
write_runlog(ERROR, "Valid units for this parameter \"%s\" is \"ms\".\n", param);
return CM_ERROR;
}
endPtr += UNIT_BITNESS;
}
if (unit == UNIT_S) {
if ((strncmp(endPtr, "s", UNIT_BITNESS) != 0)) {
write_runlog(ERROR, "Valid units for this parameter \"%s\" is \"s\".\n", param);
return CM_ERROR;
}
endPtr += UNIT_BITNESS;
}
if (unit == UNIT_MIN) {
if (strncmp(endPtr, "min", UNIT_BITNESS) != 0) {
write_runlog(ERROR, "Valid units for this parameter \"%s\" is \"min\".\n", param);
return CM_ERROR;
}
endPtr += UNIT_BITNESS;
}
if (unit == UNIT_H) {
if (strncmp(endPtr, "h", UNIT_BITNESS) != 0) {
write_runlog(ERROR, "Valid units for this parameter \"%s\" is \"h\".\n", param);
return CM_ERROR;
}
endPtr += UNIT_BITNESS;
}
if (unit == UNIT_D) {
if (strncmp(endPtr, "d", UNIT_BITNESS) != 0) {
write_runlog(ERROR, "Valid units for this parameter \"%s\" is \"d\".\n", param);
return CM_ERROR;
}
endPtr += UNIT_BITNESS;
}
return CM_SUCCESS;
}
static status_t ProcessUnit(const UnitType &unit, char *&endPtr, const char *param)
{
if (unit == UNIT_ERROR) {
write_runlog(ERROR, "Invalid units for this parameter \"%s\".\n", param);
return CM_ERROR;
}
if (ProcessMemUnit(unit, endPtr, param) != CM_SUCCESS) {
return CM_ERROR;
}
if (ProcessTimeUnit(unit, endPtr, param) != CM_SUCCESS) {
return CM_ERROR;
}
return CM_SUCCESS;
}
static status_t ParseIntegerValue(const char *param, const char *value, const char *listUnit, int64 &resultInt)
{
int64 intVal;
UnitType unit;
long double tmpDoubleVal;
char *endPtr = NULL;
bool haveSpace = false;
errno = 0;
intVal = strtoll(value, &endPtr, 0);
if (endPtr == value || errno == ERANGE) {
return CM_ERROR;
}
tmpDoubleVal = (long double)intVal;
while (isspace((unsigned char)*endPtr)) {
haveSpace = true;
endPtr++;
}
if (*endPtr != '\0') {
if (listUnit == NULL || listUnit[0] == '\0') {
write_runlog(DEBUG1, "The unit info is NULL.\n");
return CM_ERROR;
}
if (haveSpace) {
write_runlog(ERROR, "There should not hava space between value and unit.\n");
return CM_ERROR;
}
unit = GetParamUnit(listUnit);
if (ProcessUnit(unit, endPtr, param) != CM_SUCCESS) {
return CM_ERROR;
}
}
while (isspace((unsigned char)*endPtr)) {
endPtr++;
}
if (*endPtr != '\0') {
write_runlog(ERROR, "There are extra characters after the unit.\n");
return CM_ERROR;
}
if (tmpDoubleVal > LLONG_MAX || tmpDoubleVal < LLONG_MIN) {
write_runlog(ERROR, "The value is too large or too small.\n");
return CM_ERROR;
}
resultInt = (int64)tmpDoubleVal;
return CM_SUCCESS;
}
static status_t GetMinMaxValue(const char *listValue, ParamMinMaxValue &range)
{
int ret;
char* ptr;
char* buf = NULL;
const char *delim = ",";
char tmpListVal[MAX_PATH_LEN] = {0};
ret = snprintf_s(tmpListVal, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s", listValue);
securec_check_intval(ret, (void)ret);
ptr = strtok_r(tmpListVal, delim, &buf);
if (ptr == NULL) {
write_runlog(ERROR, "The minimum value information is incorrect.\n");
return CM_ERROR;
}
ret = snprintf_s(range.minValStr, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s", ptr);
securec_check_intval(ret, (void)ret);
ptr = strtok_r(NULL, delim, &buf);
if (ptr == NULL) {
write_runlog(ERROR, "The maximum value information is incorrect.\n");
return CM_ERROR;
}
ret = snprintf_s(range.maxValStr, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s", ptr);
securec_check_intval(ret, (void)ret);
ptr = strtok_r(NULL, delim, &buf);
if (ptr != NULL) {
write_runlog(ERROR, "The min and max information for parameter is incorrect.\n");
return CM_ERROR;
}
return CM_SUCCESS;
}
static status_t CheckIntTypeValue(const char *param, const char *value, const char *listValue, const char *listUnit)
{
int64 intMinVal = LLONG_MIN;
int64 intMaxVal = LLONG_MAX;
int64 newIntVal = INT_MIN;
ParamMinMaxValue range = {{0}};
if (ParseIntegerValue(param, value, listUnit, newIntVal) != CM_SUCCESS) {
return CM_ERROR;
}
if (GetMinMaxValue(listValue, range) != CM_SUCCESS) {
return CM_ERROR;
}
if (range.minValStr[0] == '\0' || range.maxValStr[0] == '\0') {
write_runlog(ERROR, "The min and max information for parameter \"%s\" is incorrect.\n", param);
return CM_ERROR;
}
if ((ParseIntegerValue(param, range.minValStr, NULL, intMinVal) != CM_SUCCESS) ||
(ParseIntegerValue(param, range.maxValStr, NULL, intMaxVal) != CM_SUCCESS)) {
write_runlog(ERROR, "The minmax value of parameter \"%s\" requires an integer value.\n", param);
return CM_ERROR;
}
if (newIntVal < intMinVal || newIntVal > intMaxVal) {
write_runlog(ERROR, "The value %ld is outside the valid range for parameter \"%s\" (%ld .. %ld).\n",
newIntVal, param, intMinVal, intMaxVal);
return CM_ERROR;
}
return CM_SUCCESS;
}
static status_t CheckStringLen(const char *value)
{
if (strlen(value) > MAX_PATH_LEN) {
write_runlog(ERROR, "The string value \"%s\" is longer than 1024.\n", value);
return CM_ERROR;
}
return CM_SUCCESS;
}
static status_t CheckDdbLogLevel(const char *param, const char *value)
{
int ret;
char* ptr;
char* buf = NULL;
const char *delim = "|";
char tmpValue[MAX_PATH_LEN] = {0};
ret = snprintf_s(tmpValue, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s", value);
securec_check_intval(ret, (void)ret);
ptr = strtok_r(tmpValue, delim, &buf);
if (ptr == NULL) {
return CM_ERROR;
}
while (ptr != NULL) {
uint32 listNums = lengthof(g_ddbLogLevelList);
if (!IsStringInList(ptr, g_ddbLogLevelList, listNums)) {
write_runlog(ERROR, "The %s is outside the valid range for parameter \"%s\".\n", ptr, param);
return CM_ERROR;
}
ptr = strtok_r(NULL, delim, &buf);
}
return CM_SUCCESS;
}
static status_t CheckDdbMaxLogFileSize(const char *value)
{
int pos = 0;
int size = 0;
int endPos = (int)strlen(value) - 1;
if (value[endPos] != 'M') {
write_runlog(ERROR, "Valid units for parameter \"ddb_max_log_file_size\" is \"M\".\n");
return CM_ERROR;
}
for (int i = endPos - 1; i >= 0; --i) {
if (value[i] > '9' || value[i] < '0') {
write_runlog(ERROR, "The value \"%s\" is outside the valid range [1M, 1000M].\n", value);
return CM_ERROR;
}
size += ((int)(value[i] - '0') * (int)pow(DECIMAL_NOTATION, pos));
++pos;
if (size > MAX_DDB_LOG_FILE_SIZE) {
write_runlog(ERROR, "The value \"%s\" is outside the valid range [1M, 1000M].\n", value);
return CM_ERROR;
}
}
if (size < 1) {
write_runlog(ERROR, "The value \"%s\" is outside the valid range [1M, 1000M].\n", value);
return CM_ERROR;
}
return CM_SUCCESS;
}
static bool IsValueSymbolRight(const char *value)
{
int symbolCount = 0;
for (int i = 0; value[i] != '\0'; ++i) {
if (value[i] == ',') {
++symbolCount;
}
}
if (symbolCount != THRESHOLD_FORMAT) {
return false;
}
return true;
}
static bool IsParamValueRight(const char *value)
{
int result;
if (value == NULL) {
write_runlog(ERROR, "The environment_threshold value = NULL.\n");
return false;
}
if (CM_is_str_all_digit(value) != 0) {
write_runlog(ERROR, "The element(%s) in environment_threshold parameter value, is not digit.\n", value);
return false;
}
result = (int)strtol(value, NULL, DECIMAL_NOTATION);
if (result < THRESHOLD_MIN_VALUE || result > THRESHOLD_MAX_VALUE) {
write_runlog(ERROR, "The element(%s) in environment_threshold parameter value, out of range[0, 100].\n", value);
return false;
}
return true;
}
static status_t CheckEnvThresholdSize(const char *value)
{
int valueNum = THRESHOLD_FORMAT + 1;
char *pLeft = NULL;
char *pValue;
char envStr[CM_PATH_LENGTH] = {0};
if (strcmp(value, "") == 0) {
write_runlog(DEBUG1, "The value is NULL.\n");
return CM_ERROR;
}
errno_t rc = strcpy_s(envStr, CM_PATH_LENGTH, value);
securec_check_errno(rc, (void)rc);
char *tmp = trim(envStr);
write_runlog(DEBUG1, "environment_threshold, tmp=%s.\n", tmp);
if (tmp[strlen(tmp) - 1] == ')') {
tmp[strlen(tmp) - 1] = '\0';
} else {
write_runlog(ERROR, "The parameter value's format is wrong, current example: \"(0,0,0,0,0)\".\n");
return CM_ERROR;
}
if (tmp[0] == '(') {
tmp++;
} else {
write_runlog(ERROR, "The parameter value's format is wrong, current example: \"(0,0,0,0,0)\".\n");
return CM_ERROR;
}
if (!IsValueSymbolRight(tmp)) {
write_runlog(ERROR, "The parameter value's format is wrong, current example: \"(0,0,0,0,0)\".\n");
return CM_ERROR;
}
pValue = strtok_r(tmp, ",", &pLeft);
while (valueNum--) {
if (!IsParamValueRight(pValue)) {
return CM_ERROR;
}
pValue = strtok_r(NULL, ",", &pLeft);
}
return CM_SUCCESS;
}
static bool ParseUint32Text(const char *text, uint32 *value)
{
if (text == NULL || text[0] == '\0' || value == NULL) {
return false;
}
char *endPtr = NULL;
errno = 0;
unsigned long parsedValue = strtoul(text, &endPtr, DECIMAL_NOTATION);
if (errno != 0 || endPtr == text || *endPtr != '\0' || parsedValue > UINT_MAX) {
return false;
}
*value = (uint32)parsedValue;
return true;
}
static status_t CheckXalarmNodeMap(const char *value)
{
if (value == NULL || value[0] == '\0') {
write_runlog(ERROR, "The value of xalarm_node_map is empty.\n");
return CM_ERROR;
}
if (g_node_num == 0 || g_node_num > CM_NODE_MAXNUM) {
write_runlog(ERROR, "The cluster node count is invalid: %u.\n", g_node_num);
return CM_ERROR;
}
char mapText[MAX_PATH_LEN] = {0};
errno_t rc = strcpy_s(mapText, MAX_PATH_LEN, value);
securec_check_errno(rc, (void)rc);
bool nodeIdSeen[CM_NODE_MAXNUM + 1] = {false};
uint32 cnaList[CM_NODE_MAXNUM] = {0};
uint32 mapCount = 0;
char *savePtr = NULL;
char *entry = strtok_r(mapText, ";", &savePtr);
while (entry != NULL) {
char *pairText = trim(entry);
if (pairText == NULL || pairText[0] == '\0') {
write_runlog(ERROR, "Invalid xalarm_node_map item, empty nodeId:cna pair.\n");
return CM_ERROR;
}
char *sep = strchr(pairText, ':');
if (sep == NULL || strchr(sep + 1, ':') != NULL) {
write_runlog(ERROR, "Invalid xalarm_node_map item \"%s\", format must be nodeId:cna.\n", pairText);
return CM_ERROR;
}
*sep = '\0';
char *nodeIdText = trim(pairText);
char *cnaText = trim(sep + 1);
uint32 nodeId = 0;
uint32 cna = 0;
if (!ParseUint32Text(nodeIdText, &nodeId) || !ParseUint32Text(cnaText, &cna)) {
write_runlog(ERROR, "Invalid xalarm_node_map item \"%s:%s\", nodeId and cna must be positive integers.\n",
nodeIdText, cnaText);
return CM_ERROR;
}
if (nodeId == 0 || nodeId > g_node_num || cna == 0) {
write_runlog(ERROR, "xalarm_node_map item out of range, nodeId=%u (valid 1..%u), cna=%u.\n",
nodeId, g_node_num, cna);
return CM_ERROR;
}
if (nodeIdSeen[nodeId]) {
write_runlog(ERROR, "Duplicated nodeId in xalarm_node_map: %u.\n", nodeId);
return CM_ERROR;
}
for (uint32 i = 0; i < mapCount; ++i) {
if (cnaList[i] == cna) {
write_runlog(ERROR, "Duplicated cna in xalarm_node_map: %u.\n", cna);
return CM_ERROR;
}
}
nodeIdSeen[nodeId] = true;
cnaList[mapCount++] = cna;
if (mapCount > g_node_num) {
write_runlog(ERROR, "Too many xalarm_node_map items, expected %u.\n", g_node_num);
return CM_ERROR;
}
entry = strtok_r(NULL, ";", &savePtr);
}
if (mapCount != g_node_num) {
write_runlog(ERROR, "The number of xalarm_node_map items (%u) must equal cluster node count (%u).\n",
mapCount, g_node_num);
return CM_ERROR;
}
for (uint32 nodeId = 1; nodeId <= g_node_num; ++nodeId) {
if (!nodeIdSeen[nodeId]) {
write_runlog(ERROR, "xalarm_node_map missing nodeId %u, it must contain 1..%u exactly once.\n",
nodeId, g_node_num);
return CM_ERROR;
}
}
return CM_SUCCESS;
}
static status_t CheckStringTypeValue(const char *param, const char *value)
{
size_t valueLen = strlen(value);
for (size_t i = 0; i < valueLen; ++i) {
if (value[i] == ' ') {
write_runlog(ERROR, "The parameter value(%s) exists illegal character:\" \".\n", value);
return CM_ERROR;
}
}
if ((strncmp(param, "log_dir", strlen("log_dir")) == 0) ||
(strncmp(param, "alarm_component", strlen("alarm_component")) == 0) ||
(strncmp(param, "unix_socket_directory", strlen("unix_socket_directory")) == 0)) {
return CheckStringLen(value);
}
if (strncmp(param, "ddb_log_level", strlen("ddb_log_level")) == 0) {
return CheckDdbLogLevel(param, value);
}
if (strncmp(param, "ddb_max_log_file_size", strlen("ddb_max_log_file_size")) == 0) {
return CheckDdbMaxLogFileSize(value);
}
if (strncmp(param, "environment_threshold", strlen("environment_threshold")) == 0) {
return CheckEnvThresholdSize(value);
}
if (strncmp(param, "event_triggers", strlen("event_triggers")) == 0) {
return CheckEventTriggers(value);
}
if (strncmp(param, "xalarm_node_map", strlen("xalarm_node_map")) == 0) {
return CheckXalarmNodeMap(value);
}
return CM_SUCCESS;
}
static status_t CheckParamValue(const char *param, const char *newValue, const ParamEnumEntry &varList)
{
switch (varList.type) {
case CM_PARA_BOOL:
return CheckBoolTypeValue(param, newValue);
case CM_PARA_ENUM:
return CheckEnumTypeValue(param, newValue, varList.value);
case CM_PARA_INT:
return CheckIntTypeValue(param, newValue, varList.value, varList.unit);
case CM_PARA_STRING:
return CheckStringTypeValue(param, newValue);
case CM_PARA_ERROR:
default:
break;
}
return CM_ERROR;
}
static uint32 CleanZeroOfInt(const char *value, uint32 valueLen)
{
for (uint32 i = 0; i < (valueLen - 1); ++i) {
if (value[i] != '0') {
return i;
}
}
return (valueLen - 1);
}
static status_t GetNewValue(const CmParaType &type, char *newValue, const char *value, int valueLen, const char *param)
{
int ret;
if (type == CM_PARA_ENUM) {
if (strchr(value, ',') != NULL) {
if (!((value[0] == '\'' || value[0] == '"') && (value[0] == value[valueLen - 1]))) {
write_runlog(ERROR, "The value \"%s\" for parameter \"%s\" is incorrect. Please do it like this "
"\"parameter = \'value\'\".\n", value, param);
return CM_ERROR;
}
}
}
if (type == CM_PARA_INT || type == CM_PARA_ENUM || type == CM_PARA_BOOL) {
char tmpValue[MAX_PATH_LEN] = {0};
if ((value[0] == '\'' || value[0] == '"') && (value[0] == value[valueLen - 1])) {
for (int i = 1, j = 0; i < valueLen - 1 && j < MAX_PATH_LEN; i++, j++) {
tmpValue[j] = value[i];
}
} else {
ret = snprintf_s(tmpValue, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s", value);
securec_check_intval(ret, (void)ret);
}
uint32 pos = 0;
if (type == CM_PARA_INT) {
pos = CleanZeroOfInt(tmpValue, (uint32)strlen(tmpValue));
}
ret = snprintf_s(newValue, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s", (tmpValue + pos));
securec_check_intval(ret, (void)ret);
}
if (type == CM_PARA_STRING) {
ret = snprintf_s(newValue, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s", value);
securec_check_intval(ret, (void)ret);
}
return CM_SUCCESS;
}
static bool IsParameterValueValid(const char *infoStr, const char *param, const char *value)
{
errno_t rc;
ParamEnumEntry varList;
int valueLen;
char newValue[MAX_PATH_LEN] = {0};
rc = memset_s(&varList, sizeof(varList), 0, sizeof(varList));
securec_check_errno(rc, (void)rc);
varList.type = CM_PARA_ERROR;
if (ParseParamInfo(infoStr, varList) != CM_SUCCESS) {
write_runlog(LOG, "Get parameter \"%s\" conf info error, can't do set.\n", param);
return false;
}
if (varList.message[0] != '\0') {
write_runlog(LOG, "NOTICE: %s\n", varList.message);
}
valueLen = (int)strlen(value);
if (GetNewValue(varList.type, newValue, value, valueLen, param) != CM_SUCCESS) {
return false;
}
if (CheckParamValue(param, newValue, varList) != CM_SUCCESS) {
if (varList.type != CM_PARA_ERROR) {
write_runlog(ERROR, "The value \"%s\" for parameter \"%s\" is incorrect, requires a %s value\n",
value, param, g_valueTypeStr[varList.type]);
} else {
write_runlog(ERROR, "The value \"%s\" for parameter \"%s\" is incorrect.\n", value, param);
}
return false;
}
return true;
}
static status_t CheckParameter(const GucOption &gucCtx)
{
char *oneParamInfo = GetOneParamInfo(gucCtx);
if (oneParamInfo == NULL || oneParamInfo[0] == '\0') {
write_runlog(ERROR, "The parameter \"%s\" is incorrect. Please check if the parameter in the required range.\n",
gucCtx.parameter);
free(oneParamInfo);
return CM_ERROR;
}
if (!IsParameterValueValid(oneParamInfo, gucCtx.parameter, gucCtx.value)) {
free(oneParamInfo);
return CM_ERROR;
}
free(oneParamInfo);
return CM_SUCCESS;
}
status_t CheckGucOptionValidate(const GucOption &gucCtx)
{
if (CheckParameterNameType(gucCtx.parameter) != CM_SUCCESS) {
return CM_ERROR;
}
if (CheckParameterValueType(gucCtx.value) != CM_SUCCESS) {
return CM_ERROR;
}
if (CheckParameter(gucCtx) != CM_SUCCESS) {
return CM_ERROR;
}
return CM_SUCCESS;
}
static EventTriggerType GetTriggerTypeFromStr(const char *typeStr)
{
for (int i = EVENT_START; i < EVENT_COUNT; ++i) {
if (strcmp(typeStr, triggerTypeStringMap[i].typeStr) == 0) {
return triggerTypeStringMap[i].type;
}
}
write_runlog(ERROR, "Event trigger type %s is not supported.\n", typeStr);
return EVENT_UNKNOWN;
}
* check trigger item, key and value can't be empty and must be string,
* value must be shell script file, current user has right permission.
*/
static status_t CheckEventTriggersItem(const cJSON *item)
{
if (!cJSON_IsString(item)) {
write_runlog(ERROR, "The trigger value must be string.\n");
return CM_ERROR;
}
char *valuePtr = item->valuestring;
if (valuePtr == NULL || strlen(valuePtr) == 0) {
write_runlog(ERROR, "The trigger value can't be empty.\n");
return CM_ERROR;
}
if (valuePtr[0] != '/') {
write_runlog(ERROR, "The trigger script path must be absolute path.\n");
return CM_ERROR;
}
const char *extention = ".sh";
const size_t shExtLen = strlen(extention);
size_t pathLen = strlen(valuePtr);
if (pathLen < shExtLen ||
strncmp((valuePtr + (pathLen - shExtLen)), extention, shExtLen) != 0) {
write_runlog(ERROR, "The trigger value %s is not shell script.\n", valuePtr);
return CM_ERROR;
}
if (access(valuePtr, F_OK) != 0) {
write_runlog(ERROR, "The trigger script %s is not a file or does not exist.\n", valuePtr);
return CM_ERROR;
}
if (access(valuePtr, R_OK | X_OK) != 0) {
write_runlog(ERROR, "Current user has no permission to access the "
"trigger script %s.\n", valuePtr);
return CM_ERROR;
}
return CM_SUCCESS;
}
* event_triggers sample:
* {
* "on_start": "/dir/on_start.sh",
* "on_stop": "/dir/on_stop.sh",
* "on_failover": "/dir/on_failover.sh",
* "on_switchover": "/dir/on_switchover.sh"
* }
*/
static status_t CheckEventTriggers(const char *value)
{
if (value == NULL || value[0] == 0) {
write_runlog(ERROR, "The value of event_triggers is empty.\n");
return CM_ERROR;
}
if (CheckStringLen(value) == CM_ERROR) {
return CM_ERROR;
}
cJSON *root = NULL;
root = cJSON_Parse(value);
if (!root) {
write_runlog(ERROR, "The value of event_triggers is not a json.\n");
return CM_ERROR;
}
if (!cJSON_IsObject(root)) {
write_runlog(ERROR, "The value of event_triggers must be an object.\n");
cJSON_Delete(root);
return CM_ERROR;
}
int triggerNums[EVENT_COUNT] = {0};
cJSON *item = root->child;
while (item != NULL) {
if (CheckEventTriggersItem(item) == CM_ERROR) {
cJSON_Delete(root);
return CM_ERROR;
}
char *typeStr = item->string;
EventTriggerType type = GetTriggerTypeFromStr(typeStr);
if (type == EVENT_UNKNOWN) {
write_runlog(ERROR, "The trigger type %s does support.\n", typeStr);
cJSON_Delete(root);
return CM_ERROR;
}
++triggerNums[type];
if (triggerNums[type] > 1) {
write_runlog(ERROR, "Duplicated trigger %s are supported.\n", typeStr);
cJSON_Delete(root);
return CM_ERROR;
}
item = item->next;
}
cJSON_Delete(root);
return CM_SUCCESS;
}