18 #include <ndb_global.h>
19 #include <ndb_version.h>
21 #include "InitConfigFileParser.hpp"
24 #include "ConfigInfo.hpp"
25 #include "EventLogger.hpp"
27 #include <util/SparseBitmask.hpp>
28 #include "../common/util/parse_mask.hpp"
32 const int MAX_LINE_LENGTH = 1024;
33 static void trim(
char *);
43 InitConfigFileParser::~InitConfigFileParser() {
50 InitConfigFileParser::Context::Context(
const ConfigInfo * info)
51 : m_userProperties(true), m_configValues(1000, 20) {
57 InitConfigFileParser::Context::~Context(){
67 FILE *
file = fopen(filename,
"r");
69 g_eventLogger->
error(
"Error opening '%s', error: %d, %s", filename, errno, strerror(errno));
81 char line[MAX_LINE_LENGTH];
85 ctx.m_currentSection = 0;
97 while (fgets(line, MAX_LINE_LENGTH, file)) {
102 if (isEmptyLine(line))
106 if (line[strlen(line)-1] ==
'\n')
107 line[strlen(line)-1] =
'\0';
112 if (
char* section = parseDefaultSectionHeader(line)) {
113 if(!storeSection(ctx)){
115 ctx.reportError(
"Could not store previous default section "
116 "of configuration file.");
121 ctx.
type = InitConfigFileParser::DefaultSection;
124 ctx.m_userDefaults = NULL;
125 require((ctx.m_currentInfo = m_info->getInfo(ctx.
fname)) != 0);
126 require((ctx.m_systemDefaults = m_info->getDefaults(ctx.
fname)) != 0);
133 if (
char* section = parseSectionHeader(line)) {
134 if(!storeSection(ctx)){
136 ctx.reportError(
"Could not store previous section "
137 "of configuration file.");
142 ctx.
type = InitConfigFileParser::Section;
145 ctx.m_userDefaults = getSection(ctx.
fname, ctx.m_defaults);
146 require((ctx.m_currentInfo = m_info->getInfo(ctx.
fname)) != 0);
147 require((ctx.m_systemDefaults = m_info->getDefaults(ctx.
fname)) != 0);
154 if (!parseNameValuePair(ctx, line)) {
155 ctx.reportError(
"Could not parse name-value pair in config file.");
161 ctx.reportError(
"Failure in reading");
165 if(!storeSection(ctx)) {
166 ctx.reportError(
"Could not store section of configuration file.");
170 return run_config_rules(ctx);
174 InitConfigFileParser::run_config_rules(Context& ctx)
176 for(
size_t i = 0; ConfigInfo::m_ConfigRules[
i].m_configRule != 0;
i++){
177 ctx.type = InitConfigFileParser::Undefined;
179 ctx.m_currentSection = 0;
180 ctx.m_userDefaults = 0;
181 ctx.m_currentInfo = 0;
182 ctx.m_systemDefaults = 0;
185 if(!(* ConfigInfo::m_ConfigRules[
i].m_configRule)(tmp, ctx,
186 ConfigInfo::m_ConfigRules[
i].m_ruleData))
189 for(
size_t j = 0; j<tmp.size(); j++){
191 "%s", tmp[j].m_sectionType.c_str());
192 ctx.type = InitConfigFileParser::Section;
193 ctx.m_currentSection = tmp[j].m_sectionData;
194 ctx.m_userDefaults = getSection(ctx.fname, ctx.m_defaults);
195 require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0);
196 require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0);
197 if(!storeSection(ctx))
202 Uint32 nConnections = 0;
203 Uint32 nComputers = 0;
205 Uint32 nExtConnections = 0;
206 const char * system =
"?";
207 ctx.m_userProperties.get(
"NoOfConnections", &nConnections);
208 ctx.m_userProperties.get(
"NoOfComputers", &nComputers);
209 ctx.m_userProperties.get(
"NoOfNodes", &nNodes);
210 ctx.m_userProperties.get(
"ExtNoOfConnections", &nExtConnections);
211 ctx.m_userProperties.get(
"ExtSystem", &system);
212 ctx.m_config->put(
"NoOfConnections", nConnections);
213 ctx.m_config->put(
"NoOfComputers", nComputers);
214 ctx.m_config->put(
"NoOfNodes", nNodes);
216 char tmpLine[MAX_LINE_LENGTH];
218 "EXTERNAL SYSTEM_%s:NoOfConnections", system);
219 ctx.m_config->put(tmpLine, nExtConnections);
221 return new Config(ctx.m_configValues.getConfigValues());
228 bool InitConfigFileParser::parseNameValuePair(Context& ctx,
const char* line)
230 if (ctx.m_currentSection == NULL){
231 ctx.reportError(
"Value specified outside section");
244 ctx.reportError(
"Parse error");
253 tmp_string_split[1].split(tmp_string_split2,
255 tmp_string_split[1]=tmp_string_split2[0];
261 for (
int i = 0;
i < 2;
i++)
262 tmp_string_split[
i].trim(
"\r\n \t");
265 return storeNameValuePair(ctx,
266 tmp_string_split[0].c_str(),
267 tmp_string_split[1].c_str());
272 InitConfigFileParser::storeNameValuePair(Context& ctx,
277 if (ctx.m_currentSection->contains(fname))
279 ctx.reportError(
"[%s] Parameter %s specified twice", ctx.fname, fname);
283 if (!ctx.m_currentInfo->contains(fname))
285 ctx.reportError(
"[%s] Unknown parameter: %s", ctx.fname, fname);
291 ctx.reportWarning(
"[%s] %s not yet implemented", ctx.fname, fname);
294 const char * desc = m_info->getDescription(ctx.m_currentInfo, fname);
296 ctx.reportWarning(
"[%s] %s is deprecated, use %s instead",
297 ctx.fname, fname, desc);
298 }
else if (desc == 0){
299 ctx.reportWarning(
"[%s] %s is deprecated", ctx.fname, fname);
303 const ConfigInfo::Type
type = m_info->getType(ctx.m_currentInfo, fname);
305 case ConfigInfo::CI_BOOL: {
307 if (!convertStringToBool(value, value_bool)) {
308 ctx.reportError(
"Illegal boolean value for parameter %s", fname);
311 require(ctx.m_currentSection->put(fname, value_bool));
314 case ConfigInfo::CI_INT:
315 case ConfigInfo::CI_INT64:{
317 if (!convertStringToUint64(value, value_int)) {
318 ctx.reportError(
"Illegal integer value for parameter %s", fname);
321 if (!m_info->
verify(ctx.m_currentInfo, fname, value_int)) {
322 ctx.reportError(
"Illegal value %s for parameter %s.\n"
323 "Legal values are between %llu and %llu", value, fname,
324 m_info->getMin(ctx.m_currentInfo, fname),
325 m_info->getMax(ctx.m_currentInfo, fname));
328 if(type == ConfigInfo::CI_INT){
329 require(ctx.m_currentSection->put(fname, (Uint32)value_int));
331 require(ctx.m_currentSection->put64(fname, value_int));
335 case ConfigInfo::CI_STRING:
336 require(ctx.m_currentSection->put(fname, value));
339 case ConfigInfo::CI_ENUM:{
341 if (!m_info->verify_enum(ctx.m_currentInfo, fname, value, value_int)) {
343 m_info->get_enum_values(ctx.m_currentInfo, fname, values);
344 ctx.reportError(
"Illegal value '%s' for parameter %s. "
345 "Legal values are: '%s'", value, fname,
349 require(ctx.m_currentSection->put(fname, value_int));
353 case ConfigInfo::CI_BITMASK:{
354 if (strlen(value) <= 0)
356 ctx.reportError(
"Illegal value '%s' for parameter %s. "
357 "Error: Zero length string",
361 Uint64 max = m_info->getMax(ctx.m_currentInfo, fname);
363 int res = parse_mask(value, mask);
370 desc.assign(
"Invalid syntax for bitmask");
373 desc.assfmt(
"Too large id used in bitmask, max is %llu", max);
379 ctx.reportError(
"Illegal value '%s' for parameter %s. Error: %s",
380 value, fname, desc.c_str());
383 require(ctx.m_currentSection->put(fname, value));
387 case ConfigInfo::CI_SECTION:
397 bool InitConfigFileParser::isEmptyLine(
const char* line)
const {
401 if (line[0] ==
'#')
return true;
404 for (i = 0; i < MAX_LINE_LENGTH && line[
i] !=
'\n' && line[
i] !=
'\0'; i++) {
405 if (line[i] !=
' ' && line[i] !=
'\t')
return false;
413 bool InitConfigFileParser::convertStringToUint64(
const char* s,
423 Int64 v = strtoll(s, &p, log10base);
428 if (p != &s[strlen(s)]){
429 char * tmp = strdup(p);
453 bool InitConfigFileParser::convertStringToBool(
const char* s,
bool& val) {
454 if (s == NULL)
return false;
455 if (strlen(s) == 0)
return false;
457 if (!strcmp(s,
"Y") || !strcmp(s,
"y") ||
458 !strcmp(s,
"Yes") || !strcmp(s,
"YES") || !strcmp(s,
"yes") ||
459 !strcmp(s,
"True") || !strcmp(s,
"TRUE") || !strcmp(s,
"true") ||
465 if (!strcmp(s,
"N") || !strcmp(s,
"n") ||
466 !strcmp(s,
"No") || !strcmp(s,
"NO") || !strcmp(s,
"no") ||
467 !strcmp(s,
"False") || !strcmp(s,
"FALSE") || !strcmp(s,
"false") ||
481 int len = strlen(str);
483 (str[len] ==
'\r' || str[len] ==
'\n' ||
484 str[len] ==
' ' || str[len] ==
'\t') &&
490 while(str[pos] ==
' ' || str[pos] ==
'\t')
493 if(str[pos] ==
'\"' && str[len] ==
'\"') {
499 memmove(str, &str[pos], len - pos + 2);
503 InitConfigFileParser::parseSectionHeader(
const char* line)
const {
504 char * tmp = strdup(line);
511 if(tmp[strlen(tmp)-1] !=
']'){
515 tmp[strlen(tmp)-1] = 0;
522 const char *tmp_alias= m_info->getAlias(tmp);
525 tmp= strdup(tmp_alias);
530 if(!m_info->isSection(tmp)) {
534 if(m_info->getInfo(tmp))
return tmp;
545 InitConfigFileParser::parseDefaultSectionHeader(
const char* line)
const {
546 static char token1[MAX_LINE_LENGTH], token2[MAX_LINE_LENGTH];
548 int no = sscanf(line,
"[%120[A-Z_a-z] %120[A-Z_a-z]]", token1, token2);
551 if (no != 2)
return NULL;
554 if (!strcasecmp(token2,
"DEFAULT") == 0)
return NULL;
556 const char *token1_alias= m_info->getAlias(token1);
557 if (token1_alias == 0)
558 token1_alias= token1;
560 if(m_info->getInfo(token1_alias)){
561 return strdup(token1_alias);
569 InitConfigFileParser::getSection(
const char *
name,
const Properties * src){
571 if(src && src->get(name, &p))
581 InitConfigFileParser::storeSection(Context& ctx){
582 if(ctx.m_currentSection == NULL)
584 for(
int i = strlen(ctx.fname) - 1; i>=0; i--){
585 ctx.fname[
i] = toupper(ctx.fname[i]);
590 if(ctx.type == InitConfigFileParser::Section)
592 if(ctx.type == InitConfigFileParser::DefaultSection)
596 if(ctx.type == InitConfigFileParser::Section){
597 for(
int i = 0; i<m_info->m_NoOfRules; i++){
599 if(!strcmp(rule.m_section,
"*") || !strcmp(rule.m_section, ctx.fname)){
600 if(!(* rule.m_sectionRule)(ctx, rule.m_ruleData)){
606 if(ctx.type == InitConfigFileParser::DefaultSection &&
607 !ctx.m_defaults->put(ctx.pname, ctx.m_currentSection))
609 ctx.reportError(
"Duplicate default section not allowed");
612 if(ctx.type == InitConfigFileParser::Section)
613 require(ctx.m_config->put(ctx.pname, ctx.m_currentSection));
614 delete ctx.m_currentSection; ctx.m_currentSection = NULL;
619 InitConfigFileParser::Context::reportError(
const char *
fmt, ...){
625 BaseString::vsnprintf(buf,
sizeof(buf)-1, fmt, ap);
627 g_eventLogger->
error(
"at line %d: %s",
634 InitConfigFileParser::Context::reportWarning(
const char * fmt, ...){
640 BaseString::vsnprintf(buf,
sizeof(buf)-1, fmt, ap);
642 g_eventLogger->
warning(
"at line %d: %s",
647 #include <my_getopt.h>
649 static int order = 1;
652 parse_mycnf_opt(
int,
const struct my_option * opt,
char * value)
654 long *app_type= (
long*) &opt->
app_type;
667 for(
unsigned i = 0; i<options.size(); i++)
669 if (options[i].app_type == 0)
675 const char* section = options[
i].comment;
682 if (strcmp(section, name) == 0)
684 const char* value = NULL;
686 switch(options[i].var_type){
690 *(Uint32*)options[i].value);
695 *(Uint64*)options[i].value);
699 value = *(
char**)options[i].value;
705 const char* fname = options[
i].name;
706 if (!storeNameValuePair(ctx, fname, value))
718 strcpy(ctx.
fname, name);
719 ctx.
type = InitConfigFileParser::DefaultSection;
721 ctx.m_userDefaults = NULL;
722 require((ctx.m_currentInfo = m_info->getInfo(ctx.
fname)) != 0);
723 require((ctx.m_systemDefaults = m_info->getDefaults(ctx.
fname)) != 0);
724 if(store_in_properties(options, ctx, name))
725 return storeSection(ctx);
734 const char * argv[] = {
"ndb_mgmd", 0, 0, 0, 0 };
739 const char *save_file = my_defaults_file;
740 #if MYSQL_VERSION_ID >= 50508
743 char *save_extra_file = my_defaults_extra_file;
744 const char *save_group_suffix = my_defaults_group_suffix;
746 if (my_defaults_file)
748 file.
assfmt(
"--defaults-file=%s", my_defaults_file);
749 argv[argc++] = file.
c_str();
752 if (my_defaults_extra_file)
754 extra_file.
assfmt(
"--defaults-extra-file=%s", my_defaults_extra_file);
755 argv[argc++] = extra_file.
c_str();
758 if (my_defaults_group_suffix)
760 group_suffix.
assfmt(
"--defaults-group-suffix=%s",
761 my_defaults_group_suffix);
762 argv[argc++] = group_suffix.
c_str();
765 char ** tmp = (
char**)argv;
766 int ret = load_defaults(
"my", groups, &argc, &tmp);
768 my_defaults_file = save_file;
769 my_defaults_extra_file = save_extra_file;
770 my_defaults_group_suffix = save_group_suffix;
774 return handle_options(&argc, &tmp, options.getBase(), parse_mycnf_opt);
784 const char *groups[])
788 for(i = 0; i<options.size(); i++)
790 if(options[i].comment && strcmp(options[i].comment, name) == 0)
792 options[
i].app_type = 0;
793 copy.push_back(options[i]);
798 memset(&end, 0,
sizeof(end));
801 if (load_defaults(copy, groups))
804 return store_in_properties(copy, ctx, name);
813 for(i = 0; i<ConfigInfo::m_NoOfParams; i++)
817 memset(&opt, 0,
sizeof(opt));
820 case ConfigInfo::CI_BOOL:
821 opt.
value = (uchar **)malloc(
sizeof(
int));
824 case ConfigInfo::CI_INT:
825 opt.
value = (uchar**)malloc(
sizeof(uint));
828 case ConfigInfo::CI_INT64:
829 opt.
value = (uchar**)malloc(
sizeof(Uint64));
832 case ConfigInfo::CI_ENUM:
833 case ConfigInfo::CI_STRING:
834 case ConfigInfo::CI_BITMASK:
835 opt.
value = (uchar**)malloc(
sizeof(
char *));
841 opt.
name = param._fname;
846 options.push_back(opt);
850 struct my_option *ndbd, *ndb_mgmd, *mysqld, *api;
855 Uint32 idx = options.size();
858 memset(&opt, 0,
sizeof(opt));
861 opt.
value = (uchar**)malloc(
sizeof(
char*));
864 options.push_back(opt);
866 opt.
name =
"ndb_mgmd";
868 opt.
value = (uchar**)malloc(
sizeof(
char*));
871 options.push_back(opt);
875 opt.
value = (uchar**)malloc(
sizeof(
char*));
878 options.push_back(opt);
882 opt.
value = (uchar**)malloc(
sizeof(
char*));
885 options.push_back(opt);
887 memset(&opt, 0,
sizeof(opt));
888 options.push_back(opt);
890 ndbd = &options[idx];
891 ndb_mgmd = &options[idx+1];
892 mysqld = &options[idx+2];
893 api = &options[idx+3];
897 const char *groups[]= {
"cluster_config", 0 };
898 if (load_defaults(options, groups))
902 if(!handle_mycnf_defaults(options, ctx,
"DB"))
904 if(!handle_mycnf_defaults(options, ctx,
"API"))
906 if(!handle_mycnf_defaults(options, ctx,
"MGM"))
908 if(!handle_mycnf_defaults(options, ctx,
"TCP"))
910 if(!handle_mycnf_defaults(options, ctx,
"SHM"))
912 if(!handle_mycnf_defaults(options, ctx,
"SCI"))
916 struct sect {
struct my_option* src;
const char *
name; } sections[] =
925 for(i = 0; sections[
i].src; i++)
927 for(
int j = i + 1; sections[j].src; j++)
929 if (sections[j].src->app_type < sections[i].src->app_type)
931 sect swap = sections[
i];
932 sections[
i] = sections[j];
938 ctx.
type = InitConfigFileParser::Section;
940 for(i = 0; sections[
i].src; i++)
942 if (sections[i].src->app_type)
944 strcpy(ctx.
fname, sections[i].name);
945 BaseString str(*(
char**)sections[i].src->value);
947 str.
split(list,
",");
949 const char * defaults_groups[] = { 0, 0, 0 };
950 for(
unsigned j = 0; j<list.size(); j++)
957 group_idx.
assfmt(
"%s.%s.%d", groups[0],
958 sections[i].src->name, j + 1);
959 group_host.
assfmt(
"%s.%s.%s", groups[0],
960 sections[i].src->name, list[j].c_str());
961 defaults_groups[0] = group_idx.
c_str();
963 defaults_groups[1] = group_host.
c_str();
965 defaults_groups[1] = 0;
968 ctx.m_userDefaults = getSection(ctx.
fname, ctx.m_defaults);
969 require((ctx.m_currentInfo = m_info->getInfo(ctx.
fname)) != 0);
970 require((ctx.m_systemDefaults = m_info->getDefaults(ctx.
fname))!= 0);
971 if(!load_mycnf_groups(options, ctx, sections[i].name,
988 if (ctx.m_currentSection->
contains(
"HostName"))
991 const char* host_name;
992 require(ctx.m_currentSection->get(
"HostName", &host_name));
993 if (strcmp(host_name, list[j].c_str()))
995 ctx.reportError(
"Illegal value 'HostName=%s' specified for "
996 "%s, previously set to '%s'",
997 host_name, group_idx.
c_str(),
1004 require(ctx.m_currentSection->
put(
"HostName", list[j].c_str()));
1007 if(!storeSection(ctx))
1014 res = run_config_rules(ctx);
1017 for(i = 0; options[
i].name; i++)
1018 free(options[i].value);