MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
InitConfigFileParser.cpp
1 /*
2  Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 #include <ndb_global.h>
19 #include <ndb_version.h>
20 
21 #include "InitConfigFileParser.hpp"
22 #include "Config.hpp"
23 #include <NdbOut.hpp>
24 #include "ConfigInfo.hpp"
25 #include "EventLogger.hpp"
26 #include <m_string.h>
27 #include <util/SparseBitmask.hpp>
28 #include "../common/util/parse_mask.hpp"
29 
30 extern EventLogger *g_eventLogger;
31 
32 const int MAX_LINE_LENGTH = 1024; // Max length of line of text in config file
33 static void trim(char *);
34 
35 //****************************************************************************
36 // Ctor / Dtor
37 //****************************************************************************
39 {
40  m_info = new ConfigInfo();
41 }
42 
43 InitConfigFileParser::~InitConfigFileParser() {
44  delete m_info;
45 }
46 
47 //****************************************************************************
48 // Read Config File
49 //****************************************************************************
50 InitConfigFileParser::Context::Context(const ConfigInfo * info)
51  : m_userProperties(true), m_configValues(1000, 20) {
52 
53  m_config = new Properties(true);
54  m_defaults = new Properties(true);
55 }
56 
57 InitConfigFileParser::Context::~Context(){
58  if(m_config != 0)
59  delete m_config;
60 
61  if(m_defaults != 0)
62  delete m_defaults;
63 }
64 
65 Config *
66 InitConfigFileParser::parseConfig(const char * filename) {
67  FILE * file = fopen(filename, "r");
68  if(file == 0){
69  g_eventLogger->error("Error opening '%s', error: %d, %s", filename, errno, strerror(errno));
70  return 0;
71  }
72 
73  Config * ret = parseConfig(file);
74  fclose(file);
75  return ret;
76 }
77 
78 Config *
80 
81  char line[MAX_LINE_LENGTH];
82 
83  Context ctx(m_info);
84  ctx.m_lineno = 0;
85  ctx.m_currentSection = 0;
86 
87  /*************
88  * Open file *
89  *************/
90  if (file == NULL) {
91  return 0;
92  }
93 
94  /***********************
95  * While lines to read *
96  ***********************/
97  while (fgets(line, MAX_LINE_LENGTH, file)) {
98  ctx.m_lineno++;
99 
100  trim(line);
101 
102  if (isEmptyLine(line)) // Skip if line is empty or comment
103  continue;
104 
105  // End with NULL instead of newline
106  if (line[strlen(line)-1] == '\n')
107  line[strlen(line)-1] = '\0';
108 
109  /********************************
110  * 1. Parse new default section *
111  ********************************/
112  if (char* section = parseDefaultSectionHeader(line)) {
113  if(!storeSection(ctx)){
114  free(section);
115  ctx.reportError("Could not store previous default section "
116  "of configuration file.");
117  return 0;
118  }
119  BaseString::snprintf(ctx.fname, sizeof(ctx.fname), "%s", section);
120  free(section);
121  ctx.type = InitConfigFileParser::DefaultSection;
122  ctx.m_sectionLineno = ctx.m_lineno;
123  ctx.m_currentSection = new Properties(true);
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);
127  continue;
128  }
129 
130  /************************
131  * 2. Parse new section *
132  ************************/
133  if (char* section = parseSectionHeader(line)) {
134  if(!storeSection(ctx)){
135  free(section);
136  ctx.reportError("Could not store previous section "
137  "of configuration file.");
138  return 0;
139  }
140  BaseString::snprintf(ctx.fname, sizeof(ctx.fname), "%s", section);
141  free(section);
142  ctx.type = InitConfigFileParser::Section;
143  ctx.m_sectionLineno = ctx.m_lineno;
144  ctx.m_currentSection = new Properties(true);
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);
148  continue;
149  }
150 
151  /****************************
152  * 3. Parse name-value pair *
153  ****************************/
154  if (!parseNameValuePair(ctx, line)) {
155  ctx.reportError("Could not parse name-value pair in config file.");
156  return 0;
157  }
158  }
159 
160  if (ferror(file)){
161  ctx.reportError("Failure in reading");
162  return 0;
163  }
164 
165  if(!storeSection(ctx)) {
166  ctx.reportError("Could not store section of configuration file.");
167  return 0;
168  }
169 
170  return run_config_rules(ctx);
171 }
172 
173 Config*
174 InitConfigFileParser::run_config_rules(Context& ctx)
175 {
176  for(size_t i = 0; ConfigInfo::m_ConfigRules[i].m_configRule != 0; i++){
177  ctx.type = InitConfigFileParser::Undefined;
178  ctx.m_info = m_info;
179  ctx.m_currentSection = 0;
180  ctx.m_userDefaults = 0;
181  ctx.m_currentInfo = 0;
182  ctx.m_systemDefaults = 0;
183 
185  if(!(* ConfigInfo::m_ConfigRules[i].m_configRule)(tmp, ctx,
186  ConfigInfo::m_ConfigRules[i].m_ruleData))
187  return 0;
188 
189  for(size_t j = 0; j<tmp.size(); j++){
190  BaseString::snprintf(ctx.fname, sizeof(ctx.fname),
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))
198  return 0;
199  }
200  }
201 
202  Uint32 nConnections = 0;
203  Uint32 nComputers = 0;
204  Uint32 nNodes = 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);
215 
216  char tmpLine[MAX_LINE_LENGTH];
217  BaseString::snprintf(tmpLine, MAX_LINE_LENGTH,
218  "EXTERNAL SYSTEM_%s:NoOfConnections", system);
219  ctx.m_config->put(tmpLine, nExtConnections);
220 
221  return new Config(ctx.m_configValues.getConfigValues());
222 }
223 
224 //****************************************************************************
225 // Parse Name-Value Pair
226 //****************************************************************************
227 
228 bool InitConfigFileParser::parseNameValuePair(Context& ctx, const char* line)
229 {
230  if (ctx.m_currentSection == NULL){
231  ctx.reportError("Value specified outside section");
232  return false;
233  }
234 
235  // *************************************
236  // Split string at first occurrence of
237  // '=' or ':'
238  // *************************************
239 
240  Vector<BaseString> tmp_string_split;
241  if (BaseString(line).split(tmp_string_split,
242  "=:", 2) != 2)
243  {
244  ctx.reportError("Parse error");
245  return false;
246  }
247 
248  // *************************************
249  // Remove all after #
250  // *************************************
251 
252  Vector<BaseString> tmp_string_split2;
253  tmp_string_split[1].split(tmp_string_split2,
254  "#", 2);
255  tmp_string_split[1]=tmp_string_split2[0];
256 
257  // *************************************
258  // Remove leading and trailing chars
259  // *************************************
260  {
261  for (int i = 0; i < 2; i++)
262  tmp_string_split[i].trim("\r\n \t");
263  }
264 
265  return storeNameValuePair(ctx,
266  tmp_string_split[0].c_str(), // fname
267  tmp_string_split[1].c_str()); // value
268 }
269 
270 
271 bool
272 InitConfigFileParser::storeNameValuePair(Context& ctx,
273  const char* fname,
274  const char* value)
275 {
276 
277  if (ctx.m_currentSection->contains(fname))
278  {
279  ctx.reportError("[%s] Parameter %s specified twice", ctx.fname, fname);
280  return false;
281  }
282 
283  if (!ctx.m_currentInfo->contains(fname))
284  {
285  ctx.reportError("[%s] Unknown parameter: %s", ctx.fname, fname);
286  return false;
287  }
288 
289  ConfigInfo::Status status = m_info->getStatus(ctx.m_currentInfo, fname);
290  if (status == ConfigInfo::CI_NOTIMPLEMENTED) {
291  ctx.reportWarning("[%s] %s not yet implemented", ctx.fname, fname);
292  }
293  if (status == ConfigInfo::CI_DEPRECATED) {
294  const char * desc = m_info->getDescription(ctx.m_currentInfo, fname);
295  if(desc && desc[0]){
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);
300  }
301  }
302 
303  const ConfigInfo::Type type = m_info->getType(ctx.m_currentInfo, fname);
304  switch(type){
305  case ConfigInfo::CI_BOOL: {
306  bool value_bool;
307  if (!convertStringToBool(value, value_bool)) {
308  ctx.reportError("Illegal boolean value for parameter %s", fname);
309  return false;
310  }
311  require(ctx.m_currentSection->put(fname, value_bool));
312  break;
313  }
314  case ConfigInfo::CI_INT:
315  case ConfigInfo::CI_INT64:{
316  Uint64 value_int;
317  if (!convertStringToUint64(value, value_int)) {
318  ctx.reportError("Illegal integer value for parameter %s", fname);
319  return false;
320  }
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));
326  return false;
327  }
328  if(type == ConfigInfo::CI_INT){
329  require(ctx.m_currentSection->put(fname, (Uint32)value_int));
330  } else {
331  require(ctx.m_currentSection->put64(fname, value_int));
332  }
333  break;
334  }
335  case ConfigInfo::CI_STRING:
336  require(ctx.m_currentSection->put(fname, value));
337  break;
338 
339  case ConfigInfo::CI_ENUM:{
340  Uint32 value_int;
341  if (!m_info->verify_enum(ctx.m_currentInfo, fname, value, value_int)) {
342  BaseString values;
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,
346  values.c_str());
347  return false;
348  }
349  require(ctx.m_currentSection->put(fname, value_int));
350  break;
351  }
352 
353  case ConfigInfo::CI_BITMASK:{
354  if (strlen(value) <= 0)
355  {
356  ctx.reportError("Illegal value '%s' for parameter %s. "
357  "Error: Zero length string",
358  value, fname);
359  return false;
360  }
361  Uint64 max = m_info->getMax(ctx.m_currentInfo, fname);
362  SparseBitmask mask((unsigned)max);
363  int res = parse_mask(value, mask);
364  if (res < 0)
365  {
366  BaseString desc("Unknown error.");
367  switch(res)
368  {
369  case -1:
370  desc.assign("Invalid syntax for bitmask");
371  break;
372  case -2:
373  desc.assfmt("Too large id used in bitmask, max is %llu", max);
374  break;
375  default:
376  break;
377  }
378 
379  ctx.reportError("Illegal value '%s' for parameter %s. Error: %s",
380  value, fname, desc.c_str());
381  return false;
382  }
383  require(ctx.m_currentSection->put(fname, value));
384  break;
385  }
386 
387  case ConfigInfo::CI_SECTION:
388  abort();
389  }
390  return true;
391 }
392 
393 //****************************************************************************
394 // Is Empty Line
395 //****************************************************************************
396 
397 bool InitConfigFileParser::isEmptyLine(const char* line) const {
398  int i;
399 
400  // Check if it is a comment line
401  if (line[0] == '#') return true;
402 
403  // Check if it is a line with only spaces
404  for (i = 0; i < MAX_LINE_LENGTH && line[i] != '\n' && line[i] != '\0'; i++) {
405  if (line[i] != ' ' && line[i] != '\t') return false;
406  }
407  return true;
408 }
409 
410 //****************************************************************************
411 // Convert String to Int
412 //****************************************************************************
413 bool InitConfigFileParser::convertStringToUint64(const char* s,
414  Uint64& val,
415  Uint32 log10base) {
416  if (s == NULL)
417  return false;
418  if (strlen(s) == 0)
419  return false;
420 
421  errno = 0;
422  char* p;
423  Int64 v = strtoll(s, &p, log10base);
424  if (errno != 0)
425  return false;
426 
427  long mul = 0;
428  if (p != &s[strlen(s)]){
429  char * tmp = strdup(p);
430  trim(tmp);
431  switch(tmp[0]){
432  case 'k':
433  case 'K':
434  mul = 10;
435  break;
436  case 'M':
437  mul = 20;
438  break;
439  case 'G':
440  mul = 30;
441  break;
442  default:
443  free(tmp);
444  return false;
445  }
446  free(tmp);
447  }
448 
449  val = (v << mul);
450  return true;
451 }
452 
453 bool InitConfigFileParser::convertStringToBool(const char* s, bool& val) {
454  if (s == NULL) return false;
455  if (strlen(s) == 0) return false;
456 
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") ||
460  !strcmp(s, "1")) {
461  val = true;
462  return true;
463  }
464 
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") ||
468  !strcmp(s, "0")) {
469  val = false;
470  return true;
471  }
472 
473  return false; // Failure to convert
474 }
475 
476 //****************************************************************************
477 // Parse Section Header
478 //****************************************************************************
479 static void
480 trim(char * str){
481  int len = strlen(str);
482  for(len--;
483  (str[len] == '\r' || str[len] == '\n' ||
484  str[len] == ' ' || str[len] == '\t') &&
485  len > 0;
486  len--)
487  str[len] = 0;
488 
489  int pos = 0;
490  while(str[pos] == ' ' || str[pos] == '\t')
491  pos++;
492 
493  if(str[pos] == '\"' && str[len] == '\"') {
494  pos++;
495  str[len] = 0;
496  len--;
497  }
498 
499  memmove(str, &str[pos], len - pos + 2);
500 }
501 
502 char*
503 InitConfigFileParser::parseSectionHeader(const char* line) const {
504  char * tmp = strdup(line);
505 
506  if(tmp[0] != '['){
507  free(tmp);
508  return NULL;
509  }
510 
511  if(tmp[strlen(tmp)-1] != ']'){
512  free(tmp);
513  return NULL;
514  }
515  tmp[strlen(tmp)-1] = 0;
516 
517  tmp[0] = ' ';
518  trim(tmp);
519 
520  // Get the correct header name if an alias
521  {
522  const char *tmp_alias= m_info->getAlias(tmp);
523  if (tmp_alias) {
524  free(tmp);
525  tmp= strdup(tmp_alias);
526  }
527  }
528 
529  // Lookup token among sections
530  if(!m_info->isSection(tmp)) {
531  free(tmp);
532  return NULL;
533  }
534  if(m_info->getInfo(tmp)) return tmp;
535 
536  free(tmp);
537  return NULL;
538 }
539 
540 //****************************************************************************
541 // Parse Default Section Header
542 //****************************************************************************
543 
544 char*
545 InitConfigFileParser::parseDefaultSectionHeader(const char* line) const {
546  static char token1[MAX_LINE_LENGTH], token2[MAX_LINE_LENGTH];
547 
548  int no = sscanf(line, "[%120[A-Z_a-z] %120[A-Z_a-z]]", token1, token2);
549 
550  // Not correct no of tokens
551  if (no != 2) return NULL;
552 
553  // Not correct keyword at end
554  if (!strcasecmp(token2, "DEFAULT") == 0) return NULL;
555 
556  const char *token1_alias= m_info->getAlias(token1);
557  if (token1_alias == 0)
558  token1_alias= token1;
559 
560  if(m_info->getInfo(token1_alias)){
561  return strdup(token1_alias);
562  }
563 
564  // Did not find section
565  return NULL;
566 }
567 
568 const Properties *
569 InitConfigFileParser::getSection(const char * name, const Properties * src){
570  const Properties * p;
571  if(src && src->get(name, &p))
572  return p;
573 
574  return 0;
575 }
576 
577 //****************************************************************************
578 // STORE section
579 //****************************************************************************
580 bool
581 InitConfigFileParser::storeSection(Context& ctx){
582  if(ctx.m_currentSection == NULL)
583  return true;
584  for(int i = strlen(ctx.fname) - 1; i>=0; i--){
585  ctx.fname[i] = toupper(ctx.fname[i]);
586  }
587  BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "%s", ctx.fname);
588 
589  char buf[255];
590  if(ctx.type == InitConfigFileParser::Section)
591  BaseString::snprintf(buf, sizeof(buf), "%s", ctx.fname);
592  if(ctx.type == InitConfigFileParser::DefaultSection)
593  BaseString::snprintf(buf, sizeof(buf), "%s DEFAULT", ctx.fname);
594  BaseString::snprintf(ctx.fname, sizeof(ctx.fname), "%s", buf);
595 
596  if(ctx.type == InitConfigFileParser::Section){
597  for(int i = 0; i<m_info->m_NoOfRules; i++){
598  const ConfigInfo::SectionRule & rule = m_info->m_SectionRules[i];
599  if(!strcmp(rule.m_section, "*") || !strcmp(rule.m_section, ctx.fname)){
600  if(!(* rule.m_sectionRule)(ctx, rule.m_ruleData)){
601  return false;
602  }
603  }
604  }
605  }
606  if(ctx.type == InitConfigFileParser::DefaultSection &&
607  !ctx.m_defaults->put(ctx.pname, ctx.m_currentSection))
608  {
609  ctx.reportError("Duplicate default section not allowed");
610  return false;
611  }
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;
615  return true;
616 }
617 
618 void
619 InitConfigFileParser::Context::reportError(const char * fmt, ...){
620  va_list ap;
621  char buf[1000];
622 
623  va_start(ap, fmt);
624  if (fmt != 0)
625  BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
626  va_end(ap);
627  g_eventLogger->error("at line %d: %s",
628  m_lineno, buf);
629 
630  //m_currentSection->print();
631 }
632 
633 void
634 InitConfigFileParser::Context::reportWarning(const char * fmt, ...){
635  va_list ap;
636  char buf[1000];
637 
638  va_start(ap, fmt);
639  if (fmt != 0)
640  BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
641  va_end(ap);
642  g_eventLogger->warning("at line %d: %s",
643  m_lineno, buf);
644 }
645 
646 #include <my_sys.h>
647 #include <my_getopt.h>
648 
649 static int order = 1;
650 static
651 my_bool
652 parse_mycnf_opt(int, const struct my_option * opt, char * value)
653 {
654  long *app_type= (long*) &opt->app_type;
655  if(opt->comment)
656  (*app_type)++;
657  else
658  *app_type = order++;
659  return 0;
660 }
661 
662 bool
663 InitConfigFileParser::store_in_properties(Vector<struct my_option>& options,
665  const char * name)
666 {
667  for(unsigned i = 0; i<options.size(); i++)
668  {
669  if (options[i].app_type == 0)
670  {
671  // Option not found in in my.cnf
672  continue;
673  }
674 
675  const char* section = options[i].comment;
676  if (!section)
677  {
678  // Option which is not to be saved, like "ndbd", "ndbapi", "mysqld" etc.
679  continue;
680  }
681 
682  if (strcmp(section, name) == 0)
683  {
684  const char* value = NULL;
685  char buf[32];
686  switch(options[i].var_type){
687  case GET_INT:
688  case GET_UINT:
689  BaseString::snprintf(buf, sizeof(buf), "%u",
690  *(Uint32*)options[i].value);
691  value = buf;
692  break;
693  case GET_ULL:
694  BaseString::snprintf(buf, sizeof(buf), "%llu",
695  *(Uint64*)options[i].value);
696  value = buf;
697  break;
698  case GET_STR:
699  value = *(char**)options[i].value;
700  break;
701  default:
702  abort();
703  }
704 
705  const char* fname = options[i].name;
706  if (!storeNameValuePair(ctx, fname, value))
707  return false;
708  }
709  }
710  return true;
711 }
712 
713 bool
714 InitConfigFileParser::handle_mycnf_defaults(Vector<struct my_option>& options,
716  const char * name)
717 {
718  strcpy(ctx.fname, name);
719  ctx.type = InitConfigFileParser::DefaultSection;
720  ctx.m_currentSection = new Properties(true);
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);
726  return false;
727 }
728 
729 static
730 int
731 load_defaults(Vector<struct my_option>& options, const char* groups[])
732 {
733  int argc = 1;
734  const char * argv[] = { "ndb_mgmd", 0, 0, 0, 0 };
736  BaseString extra_file;
737  BaseString group_suffix;
738 
739  const char *save_file = my_defaults_file;
740 #if MYSQL_VERSION_ID >= 50508
741  const
742 #endif
743  char *save_extra_file = my_defaults_extra_file;
744  const char *save_group_suffix = my_defaults_group_suffix;
745 
746  if (my_defaults_file)
747  {
748  file.assfmt("--defaults-file=%s", my_defaults_file);
749  argv[argc++] = file.c_str();
750  }
751 
752  if (my_defaults_extra_file)
753  {
754  extra_file.assfmt("--defaults-extra-file=%s", my_defaults_extra_file);
755  argv[argc++] = extra_file.c_str();
756  }
757 
758  if (my_defaults_group_suffix)
759  {
760  group_suffix.assfmt("--defaults-group-suffix=%s",
761  my_defaults_group_suffix);
762  argv[argc++] = group_suffix.c_str();
763  }
764 
765  char ** tmp = (char**)argv;
766  int ret = load_defaults("my", groups, &argc, &tmp);
767 
768  my_defaults_file = save_file;
769  my_defaults_extra_file = save_extra_file;
770  my_defaults_group_suffix = save_group_suffix;
771 
772  if (ret == 0)
773  {
774  return handle_options(&argc, &tmp, options.getBase(), parse_mycnf_opt);
775  }
776 
777  return ret;
778 }
779 
780 bool
781 InitConfigFileParser::load_mycnf_groups(Vector<struct my_option> & options,
783  const char * name,
784  const char *groups[])
785 {
786  unsigned i;
788  for(i = 0; i<options.size(); i++)
789  {
790  if(options[i].comment && strcmp(options[i].comment, name) == 0)
791  {
792  options[i].app_type = 0;
793  copy.push_back(options[i]);
794  }
795  }
796 
797  struct my_option end;
798  memset(&end, 0, sizeof(end));
799  copy.push_back(end);
800 
801  if (load_defaults(copy, groups))
802  return false;
803 
804  return store_in_properties(copy, ctx, name);
805 }
806 
807 Config *
809 {
810  int i;
811  Config * res = 0;
812  Vector<struct my_option> options;
813  for(i = 0; i<ConfigInfo::m_NoOfParams; i++)
814  {
815  {
816  struct my_option opt;
817  memset(&opt, 0, sizeof(opt));
819  switch(param._type){
820  case ConfigInfo::CI_BOOL:
821  opt.value = (uchar **)malloc(sizeof(int));
822  opt.var_type = GET_INT;
823  break;
824  case ConfigInfo::CI_INT:
825  opt.value = (uchar**)malloc(sizeof(uint));
826  opt.var_type = GET_UINT;
827  break;
828  case ConfigInfo::CI_INT64:
829  opt.value = (uchar**)malloc(sizeof(Uint64));
830  opt.var_type = GET_ULL;
831  break;
832  case ConfigInfo::CI_ENUM:
833  case ConfigInfo::CI_STRING:
834  case ConfigInfo::CI_BITMASK:
835  opt.value = (uchar**)malloc(sizeof(char *));
836  opt.var_type = GET_STR;
837  break;
838  default:
839  continue;
840  }
841  opt.name = param._fname;
842  opt.id = 256;
843  opt.app_type = 0;
844  opt.arg_type = REQUIRED_ARG;
845  opt.comment = param._section;
846  options.push_back(opt);
847  }
848  }
849 
850  struct my_option *ndbd, *ndb_mgmd, *mysqld, *api;
851 
855  Uint32 idx = options.size();
856  {
857  struct my_option opt;
858  memset(&opt, 0, sizeof(opt));
859  opt.name = "ndbd";
860  opt.id = 256;
861  opt.value = (uchar**)malloc(sizeof(char*));
862  opt.var_type = GET_STR;
863  opt.arg_type = REQUIRED_ARG;
864  options.push_back(opt);
865 
866  opt.name = "ndb_mgmd";
867  opt.id = 256;
868  opt.value = (uchar**)malloc(sizeof(char*));
869  opt.var_type = GET_STR;
870  opt.arg_type = REQUIRED_ARG;
871  options.push_back(opt);
872 
873  opt.name = "mysqld";
874  opt.id = 256;
875  opt.value = (uchar**)malloc(sizeof(char*));
876  opt.var_type = GET_STR;
877  opt.arg_type = REQUIRED_ARG;
878  options.push_back(opt);
879 
880  opt.name = "ndbapi";
881  opt.id = 256;
882  opt.value = (uchar**)malloc(sizeof(char*));
883  opt.var_type = GET_STR;
884  opt.arg_type = REQUIRED_ARG;
885  options.push_back(opt);
886 
887  memset(&opt, 0, sizeof(opt));
888  options.push_back(opt);
889 
890  ndbd = &options[idx];
891  ndb_mgmd = &options[idx+1];
892  mysqld = &options[idx+2];
893  api = &options[idx+3];
894  }
895 
896  Context ctx(m_info);
897  const char *groups[]= { "cluster_config", 0 };
898  if (load_defaults(options, groups))
899  goto end;
900 
901  ctx.m_lineno = 0;
902  if(!handle_mycnf_defaults(options, ctx, "DB"))
903  goto end;
904  if(!handle_mycnf_defaults(options, ctx, "API"))
905  goto end;
906  if(!handle_mycnf_defaults(options, ctx, "MGM"))
907  goto end;
908  if(!handle_mycnf_defaults(options, ctx, "TCP"))
909  goto end;
910  if(!handle_mycnf_defaults(options, ctx, "SHM"))
911  goto end;
912  if(!handle_mycnf_defaults(options, ctx, "SCI"))
913  goto end;
914 
915  {
916  struct sect { struct my_option* src; const char * name; } sections[] =
917  {
918  { ndb_mgmd, "MGM" }
919  ,{ ndbd, "DB" }
920  ,{ mysqld, "API" }
921  ,{ api, "API" }
922  ,{ 0, 0 }, { 0, 0 }
923  };
924 
925  for(i = 0; sections[i].src; i++)
926  {
927  for(int j = i + 1; sections[j].src; j++)
928  {
929  if (sections[j].src->app_type < sections[i].src->app_type)
930  {
931  sect swap = sections[i];
932  sections[i] = sections[j];
933  sections[j] = swap;
934  }
935  }
936  }
937 
938  ctx.type = InitConfigFileParser::Section;
939  ctx.m_sectionLineno = ctx.m_lineno;
940  for(i = 0; sections[i].src; i++)
941  {
942  if (sections[i].src->app_type)
943  {
944  strcpy(ctx.fname, sections[i].name);
945  BaseString str(*(char**)sections[i].src->value);
946  Vector<BaseString> list;
947  str.split(list, ",");
948 
949  const char * defaults_groups[] = { 0, 0, 0 };
950  for(unsigned j = 0; j<list.size(); j++)
951  {
952  // Remove leading and trailing spaces from hostname
953  list[j].trim();
954 
955  BaseString group_idx;
956  BaseString group_host;
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();
962  if(list[j].length())
963  defaults_groups[1] = group_host.c_str();
964  else
965  defaults_groups[1] = 0;
966 
967  ctx.m_currentSection = new Properties(true);
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,
972  defaults_groups))
973  goto end;
974 
975  // The [cluster_config] section in my.cnf specifies the hostname,
976  // but it can also be specified a second time in the nodes section
977  // make sure they match if specified in both places, else
978  // save the value from cluster_config section
979  //
980  // Example:
981  // [cluster_config]
982  // ndbd=hostname1
983  // ^^^^^^^^^
984  // [cluster_config.ndbd.1]
985  // HostName=hostname1
986  // ^^^^^^^^^
987  //
988  if (ctx.m_currentSection->contains("HostName"))
989  {
990  // HostName specified a second time, check that it matches
991  const char* host_name;
992  require(ctx.m_currentSection->get("HostName", &host_name));
993  if (strcmp(host_name, list[j].c_str()))
994  {
995  ctx.reportError("Illegal value 'HostName=%s' specified for "
996  "%s, previously set to '%s'",
997  host_name, group_idx.c_str(),
998  list[j].c_str());
999  goto end;
1000  }
1001  }
1002  else
1003  {
1004  require(ctx.m_currentSection->put("HostName", list[j].c_str()));
1005  }
1006 
1007  if(!storeSection(ctx))
1008  goto end;
1009  }
1010  }
1011  }
1012  }
1013 
1014  res = run_config_rules(ctx);
1015 
1016 end:
1017  for(i = 0; options[i].name; i++)
1018  free(options[i].value);
1019 
1020  return res;
1021 }
1022 
1023 template class Vector<struct my_option>;
1024 
1025 /*
1026  See include/my_getopt.h for the declaration of struct my_option
1027 */