InitConfigFileParser.cpp 25.5 KB
Newer Older
1 2 3 4
/* Copyright (C) 2003 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
unknown's avatar
unknown committed
5
   the Free Software Foundation; version 2 of the License.
6 7 8 9 10 11 12 13 14 15

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

16 17
#include <ndb_global.h>

18 19 20 21 22
#include "InitConfigFileParser.hpp"
#include "Config.hpp"
#include "MgmtErrorReporter.hpp"
#include <NdbOut.hpp>
#include "ConfigInfo.hpp"
unknown's avatar
unknown committed
23
#include <m_string.h>
24

unknown's avatar
unknown committed
25
const int MAX_LINE_LENGTH = 1024;  // Max length of line of text in config file
26 27 28 29 30 31 32
static void trim(char *);

static void require(bool v) { if(!v) abort();}

//****************************************************************************
//  Ctor / Dtor
//****************************************************************************
unknown's avatar
ndb -  
unknown committed
33 34
InitConfigFileParser::InitConfigFileParser(FILE * out)
{
35
  m_info = new ConfigInfo();
unknown's avatar
ndb -  
unknown committed
36
  m_errstream = out ? out : stdout;
37 38 39 40 41 42 43 44 45
}

InitConfigFileParser::~InitConfigFileParser() {
  delete m_info;
}

//****************************************************************************
//  Read Config File
//****************************************************************************
unknown's avatar
ndb -  
unknown committed
46
InitConfigFileParser::Context::Context(const ConfigInfo * info, FILE * out)
unknown's avatar
unknown committed
47
  :  m_userProperties(true), m_configValues(1000, 20) {
48

49 50
  m_config = new Properties(true);
  m_defaults = new Properties(true);
unknown's avatar
ndb -  
unknown committed
51
  m_errstream = out;
52 53 54 55 56 57 58 59 60 61 62 63 64 65
}

InitConfigFileParser::Context::~Context(){
  if(m_config != 0)
    delete m_config;

  if(m_defaults != 0)
    delete m_defaults;
}

Config *
InitConfigFileParser::parseConfig(const char * filename) {
  FILE * file = fopen(filename, "r");
  if(file == 0){
unknown's avatar
ndb -  
unknown committed
66
    fprintf(m_errstream, "Error opening file: %s\n", filename);
67 68
    return 0;
  }
unknown's avatar
ndb -  
unknown committed
69
  
70 71 72 73 74 75 76
  Config * ret = parseConfig(file);
  fclose(file);
  return ret;
}

Config *
InitConfigFileParser::parseConfig(FILE * file) {
77 78 79

  char line[MAX_LINE_LENGTH];

unknown's avatar
ndb -  
unknown committed
80
  Context ctx(m_info, m_errstream); 
81 82 83 84 85 86
  ctx.m_lineno = 0;
  ctx.m_currentSection = 0;

  /*************
   * Open file *
   *************/
87 88
  if (file == NULL) {
    return 0;
89 90 91 92 93
  }

  /***********************
   * While lines to read *
   ***********************/
94
  while (fgets(line, MAX_LINE_LENGTH, file)) {
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
    ctx.m_lineno++;

    trim(line);

    if (isEmptyLine(line)) // Skip if line is empty or comment
      continue;   

    // End with NULL instead of newline
    if (line[strlen(line)-1] == '\n')
      line[strlen(line)-1] = '\0';
    
    /********************************
     * 1. Parse new default section *
     ********************************/
    if (char* section = parseDefaultSectionHeader(line)) {
      if(!storeSection(ctx)){
	free(section);
	ctx.reportError("Could not store previous default section "
			"of configuration file.");
114
	return 0;
115
      }
116
      BaseString::snprintf(ctx.fname, sizeof(ctx.fname), section); free(section);
117 118
      ctx.type             = InitConfigFileParser::DefaultSection;
      ctx.m_sectionLineno  = ctx.m_lineno;
119
      ctx.m_currentSection = new Properties(true);
120
      ctx.m_userDefaults   = NULL;
121 122
      require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0);
      require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0);
123 124 125 126 127 128 129 130 131 132 133
      continue;
    }
    
    /************************
     * 2. Parse new section *
     ************************/
    if (char* section = parseSectionHeader(line)) {
      if(!storeSection(ctx)){
	free(section);
	ctx.reportError("Could not store previous section "
			"of configuration file.");
134
	return 0;
135
      }
136
      BaseString::snprintf(ctx.fname, sizeof(ctx.fname), section);
137 138 139
      free(section);
      ctx.type             = InitConfigFileParser::Section;
      ctx.m_sectionLineno  = ctx.m_lineno;      
140
      ctx.m_currentSection = new Properties(true);
141
      ctx.m_userDefaults   = getSection(ctx.fname, ctx.m_defaults);
142 143
      require((ctx.m_currentInfo    = m_info->getInfo(ctx.fname)) != 0);
      require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0);
144 145 146 147 148 149 150 151
      continue;
    }
    
    /****************************
     * 3. Parse name-value pair *
     ****************************/
    if (!parseNameValuePair(ctx, line)) {
      ctx.reportError("Could not parse name-value pair in config file.");
152
      return 0;
153 154 155
    }
  }
  
156 157 158 159 160
  if (ferror(file)){
    ctx.reportError("Failure in reading");
    return 0;
  } 

161 162
  if(!storeSection(ctx)) {
    ctx.reportError("Could not store section of configuration file.");
163
    return 0;
164
  }
unknown's avatar
unknown committed
165 166 167 168 169 170 171

  return run_config_rules(ctx);
}

Config*
InitConfigFileParser::run_config_rules(Context& ctx)
{
172 173 174 175 176 177 178 179 180 181 182 183 184
  for(size_t i = 0; ConfigInfo::m_ConfigRules[i].m_configRule != 0; i++){
    ctx.type             = InitConfigFileParser::Undefined;
    ctx.m_currentSection = 0;
    ctx.m_userDefaults   = 0;
    ctx.m_currentInfo    = 0;
    ctx.m_systemDefaults = 0;
    
    Vector<ConfigInfo::ConfigRuleSection> tmp;
    if(!(* ConfigInfo::m_ConfigRules[i].m_configRule)(tmp, ctx,
						      ConfigInfo::m_ConfigRules[i].m_ruleData))
      return 0;

    for(size_t j = 0; j<tmp.size(); j++){
185
      BaseString::snprintf(ctx.fname, sizeof(ctx.fname), tmp[j].m_sectionType.c_str());
186 187 188
      ctx.type             = InitConfigFileParser::Section;
      ctx.m_currentSection = tmp[j].m_sectionData;
      ctx.m_userDefaults   = getSection(ctx.fname, ctx.m_defaults);
189 190
      require((ctx.m_currentInfo    = m_info->getInfo(ctx.fname)) != 0);
      require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0);
191 192 193 194 195
      if(!storeSection(ctx))
	return 0;
    }
  }

196 197 198 199 200 201 202 203 204 205
  Uint32 nConnections = 0;
  Uint32 nComputers = 0;
  Uint32 nNodes = 0;
  Uint32 nExtConnections = 0;
  const char * system = "?";
  ctx.m_userProperties.get("NoOfConnections", &nConnections);
  ctx.m_userProperties.get("NoOfComputers", &nComputers);
  ctx.m_userProperties.get("NoOfNodes", &nNodes);
  ctx.m_userProperties.get("ExtNoOfConnections", &nExtConnections);
  ctx.m_userProperties.get("ExtSystem", &system);
206 207 208
  ctx.m_config->put("NoOfConnections", nConnections);
  ctx.m_config->put("NoOfComputers", nComputers);
  ctx.m_config->put("NoOfNodes", nNodes);
209 210

  char tmpLine[MAX_LINE_LENGTH];
211
  BaseString::snprintf(tmpLine, MAX_LINE_LENGTH, "EXTERNAL SYSTEM_");
212 213
  strncat(tmpLine, system, MAX_LINE_LENGTH);
  strncat(tmpLine, ":NoOfConnections", MAX_LINE_LENGTH);
214
  ctx.m_config->put(tmpLine, nExtConnections);
215
  
216 217 218 219
  Config * ret = new Config();
  ret->m_configValues = (struct ndb_mgm_configuration*)ctx.m_configValues.getConfigValues();
  ret->m_oldConfig = ctx.m_config; ctx.m_config = 0;
  return ret;
220 221 222 223 224 225
}

//****************************************************************************
//  Parse Name-Value Pair
//****************************************************************************

226 227
bool InitConfigFileParser::parseNameValuePair(Context& ctx, const char* line)
{
228 229 230 231 232 233
  if (ctx.m_currentSection == NULL){
    ctx.reportError("Value specified outside section");
    return false;
  }

  // *************************************
234 235
  //  Split string at first occurrence of 
  //  '=' or ':'
236
  // *************************************
unknown's avatar
unknown committed
237

238 239
  Vector<BaseString> tmp_string_split;
  if (BaseString(line).split(tmp_string_split,
240
			     "=:", 2) != 2)
241
  {
242 243 244 245
    ctx.reportError("Parse error");
    return false;
  }

246 247 248 249 250 251 252 253 254
  // *************************************
  //  Remove all after #
  // *************************************

  Vector<BaseString> tmp_string_split2;
  tmp_string_split[1].split(tmp_string_split2,
			    "#", 2);
  tmp_string_split[1]=tmp_string_split2[0];

255 256 257 258 259 260
  // *************************************
  // Remove leading and trailing chars
  // *************************************
  {
    for (int i = 0; i < 2; i++)
      tmp_string_split[i].trim("\r\n \t"); 
261
  }
262 263 264 265 266 267 268

  // *************************************
  // First in split is fname
  // *************************************

  const char *fname= tmp_string_split[0].c_str();

269 270 271 272 273
  if (!ctx.m_currentInfo->contains(fname)) {
    ctx.reportError("[%s] Unknown parameter: %s", ctx.fname, fname);
    return false;
  }
  ConfigInfo::Status status = m_info->getStatus(ctx.m_currentInfo, fname);
unknown's avatar
unknown committed
274
  if (status == ConfigInfo::CI_NOTIMPLEMENTED) {
275 276
    ctx.reportWarning("[%s] %s not yet implemented", ctx.fname, fname);
  }
unknown's avatar
unknown committed
277
  if (status == ConfigInfo::CI_DEPRICATED) {
278
    const char * desc = m_info->getDescription(ctx.m_currentInfo, fname);
unknown's avatar
unknown committed
279
    if(desc && desc[0]){
280 281
      ctx.reportWarning("[%s] %s is depricated, use %s instead", 
			ctx.fname, fname, desc);
unknown's avatar
unknown committed
282
    } else if (desc == 0){
283 284
      ctx.reportWarning("[%s] %s is depricated", ctx.fname, fname);
    } 
285 286 287 288 289
  }

  // ***********************
  //  Store name-value pair
  // ***********************
290 291

  return storeNameValuePair(ctx, fname, tmp_string_split[1].c_str());
292 293 294 295 296 297 298 299 300 301 302 303
}


//****************************************************************************
//  STORE NAME-VALUE pair in properties section 
//****************************************************************************

bool 
InitConfigFileParser::storeNameValuePair(Context& ctx,
					 const char* fname, 
					 const char* value) {
  
304
  const char * pname = fname;
305 306 307 308 309 310 311 312 313 314

  if (ctx.m_currentSection->contains(pname)) {
    ctx.reportError("[%s] Parameter %s specified twice", ctx.fname, fname);
    return false;
  }
  
  // ***********************
  //  Store name-value pair
  // ***********************

315 316
  const ConfigInfo::Type type = m_info->getType(ctx.m_currentInfo, fname);
  switch(type){
unknown's avatar
unknown committed
317
  case ConfigInfo::CI_BOOL: {
318 319 320 321 322 323 324 325
    bool value_bool;
    if (!convertStringToBool(value, value_bool)) {
      ctx.reportError("Illegal boolean value for parameter %s", fname);
      return false;
    }
    MGM_REQUIRE(ctx.m_currentSection->put(pname, value_bool));
    break;
  }
unknown's avatar
unknown committed
326 327
  case ConfigInfo::CI_INT:
  case ConfigInfo::CI_INT64:{
328 329
    Uint64 value_int;
    if (!convertStringToUint64(value, value_int)) {
330 331 332 333 334
      ctx.reportError("Illegal integer value for parameter %s", fname);
      return false;
    }
    if (!m_info->verify(ctx.m_currentInfo, fname, value_int)) {
      ctx.reportError("Illegal value %s for parameter %s.\n"
unknown's avatar
unknown committed
335
		      "Legal values are between %Lu and %Lu", value, fname,
336 337 338 339
		      m_info->getMin(ctx.m_currentInfo, fname), 
		      m_info->getMax(ctx.m_currentInfo, fname));
      return false;
    }
unknown's avatar
unknown committed
340
    if(type == ConfigInfo::CI_INT){
341 342 343 344
      MGM_REQUIRE(ctx.m_currentSection->put(pname, (Uint32)value_int));
    } else {
      MGM_REQUIRE(ctx.m_currentSection->put64(pname, value_int));
    }
345 346
    break;
  }
unknown's avatar
unknown committed
347
  case ConfigInfo::CI_STRING:
348 349
    MGM_REQUIRE(ctx.m_currentSection->put(pname, value));
    break;
unknown's avatar
unknown committed
350
  case ConfigInfo::CI_SECTION:
unknown's avatar
unknown committed
351
    abort();
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
  }
  return true;
}

//****************************************************************************
//  Is Empty Line
//****************************************************************************

bool InitConfigFileParser::isEmptyLine(const char* line) const {
  int i;
  
  // Check if it is a comment line
  if (line[0] == '#') return true;               

  // Check if it is a line with only spaces
  for (i = 0; i < MAX_LINE_LENGTH && line[i] != '\n' && line[i] != '\0'; i++) {
    if (line[i] != ' ' && line[i] != '\t') return false;
  }
  return true;
}

//****************************************************************************
//  Convert String to Int
//****************************************************************************
376 377
bool InitConfigFileParser::convertStringToUint64(const char* s, 
						 Uint64& val,
378 379 380 381 382 383 384 385
						 Uint32 log10base) {
  if (s == NULL)
    return false;
  if (strlen(s) == 0) 
    return false;

  errno = 0;
  char* p;
unknown's avatar
unknown committed
386
  Int64 v = strtoll(s, &p, log10base);
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
  if (errno != 0)
    return false;
  
  long mul = 0;
  if (p != &s[strlen(s)]){
    char * tmp = strdup(p);
    trim(tmp);
    switch(tmp[0]){
    case 'k':
    case 'K':
      mul = 10;
      break;
    case 'M':
      mul = 20;
      break;
    case 'G':
      mul = 30;
      break;
    default:
      free(tmp);
      return false;
    }
    free(tmp);
  }
  
  val = (v << mul);
  return true;
}

bool InitConfigFileParser::convertStringToBool(const char* s, bool& val) {
  if (s == NULL) return false;
  if (strlen(s) == 0) return false;

  if (!strcmp(s, "Y") || !strcmp(s, "y") || 
      !strcmp(s, "Yes") || !strcmp(s, "YES") || !strcmp(s, "yes") || 
422 423
      !strcmp(s, "True") || !strcmp(s, "TRUE") || !strcmp(s, "true") ||
      !strcmp(s, "1")) {
424 425 426 427 428 429
    val = true;
    return true;
  }

  if (!strcmp(s, "N") || !strcmp(s, "n") || 
      !strcmp(s, "No") || !strcmp(s, "NO") || !strcmp(s, "no") || 
430 431
      !strcmp(s, "False") || !strcmp(s, "FALSE") || !strcmp(s, "false") ||
      !strcmp(s, "0")) {
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
    val = false;
    return true;
  }
  
  return false;  // Failure to convert
}

//****************************************************************************
//  Parse Section Header
//****************************************************************************
static void
trim(char * str){
  int len = strlen(str);
  for(len--;
      (str[len] == '\r' || str[len] == '\n' || 
       str[len] == ' ' || str[len] == '\t') && 
	len > 0; 
      len--)
    str[len] = 0;
  
  int pos = 0;
  while(str[pos] == ' ' || str[pos] == '\t')
    pos++;
  
  if(str[pos] == '\"' && str[len] == '\"') {
    pos++;
    str[len] = 0;
    len--;
  }
  
  memmove(str, &str[pos], len - pos + 2);
}

char* 
InitConfigFileParser::parseSectionHeader(const char* line) const {
  char * tmp = strdup(line);

  if(tmp[0] != '['){
    free(tmp);
    return NULL;
  }

  if(tmp[strlen(tmp)-1] != ']'){
    free(tmp);
    return NULL;
  }
  tmp[strlen(tmp)-1] = 0;

  tmp[0] = ' ';
  trim(tmp);

unknown's avatar
unknown committed
483 484 485 486 487 488 489 490 491
  // Get the correct header name if an alias
  {
    const char *tmp_alias= m_info->getAlias(tmp);
    if (tmp_alias) {
      free(tmp);
      tmp= strdup(tmp_alias);
    }
  }

492
  // Lookup token among sections
unknown's avatar
unknown committed
493 494 495 496
  if(!m_info->isSection(tmp)) {
    free(tmp);
    return NULL;
  }
497 498 499 500 501 502 503 504 505 506 507 508 509 510
  if(m_info->getInfo(tmp)) return tmp;

  free(tmp);
  return NULL;
}

//****************************************************************************
//  Parse Default Section Header
//****************************************************************************

char* 
InitConfigFileParser::parseDefaultSectionHeader(const char* line) const {
  static char token1[MAX_LINE_LENGTH], token2[MAX_LINE_LENGTH];

511
  int no = sscanf(line, "[%120[A-Z_a-z] %120[A-Z_a-z]]", token1, token2);
512 513 514 515 516

  // Not correct no of tokens 
  if (no != 2) return NULL;

  // Not correct keyword at end
unknown's avatar
unknown committed
517
  if (!strcasecmp(token2, "DEFAULT") == 0) return NULL;
518

519 520 521
  const char *token1_alias= m_info->getAlias(token1);
  if (token1_alias == 0)
    token1_alias= token1;
522

523 524
  if(m_info->getInfo(token1_alias)){
    return strdup(token1_alias);
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
  }
  
  // Did not find section
  return NULL;
}

const Properties *
InitConfigFileParser::getSection(const char * name, const Properties * src){
  const Properties * p;
  if(src && src->get(name, &p))
    return p;

  return 0;
}

//****************************************************************************
//  STORE section
//****************************************************************************
bool
InitConfigFileParser::storeSection(Context& ctx){
  if(ctx.m_currentSection == NULL)
    return true;
  for(int i = strlen(ctx.fname) - 1; i>=0; i--){
    ctx.fname[i] = toupper(ctx.fname[i]);
  }
550
  BaseString::snprintf(ctx.pname, sizeof(ctx.pname), ctx.fname);
551 552
  char buf[255];
  if(ctx.type == InitConfigFileParser::Section)
553
    BaseString::snprintf(buf, sizeof(buf), "%s", ctx.fname);
554
  if(ctx.type == InitConfigFileParser::DefaultSection)
555 556
    BaseString::snprintf(buf, sizeof(buf), "%s DEFAULT", ctx.fname);
  BaseString::snprintf(ctx.fname, sizeof(ctx.fname), buf);
557 558 559
  if(ctx.type == InitConfigFileParser::Section){
    for(int i = 0; i<m_info->m_NoOfRules; i++){
      const ConfigInfo::SectionRule & rule = m_info->m_SectionRules[i];
560 561
      if(!strcmp(rule.m_section, "*") || !strcmp(rule.m_section, ctx.fname)){
	if(!(* rule.m_sectionRule)(ctx, rule.m_ruleData)){
562
	  return false;
563 564
	}
      }
565
    }
566
  }
567 568 569 570 571 572
  if(ctx.type == InitConfigFileParser::DefaultSection &&
     !ctx.m_defaults->put(ctx.pname, ctx.m_currentSection))
  {
    ctx.reportError("Duplicate default section not allowed");
    return false;
  }
573
  if(ctx.type == InitConfigFileParser::Section)
574
    require(ctx.m_config->put(ctx.pname, ctx.m_currentSection));
575 576 577 578 579 580 581 582 583 584 585
  delete ctx.m_currentSection; ctx.m_currentSection = NULL;
  return true;
}

void
InitConfigFileParser::Context::reportError(const char * fmt, ...){
  va_list ap;
  char buf[1000];
  
  va_start(ap, fmt);
  if (fmt != 0)
586
    BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
587
  va_end(ap);
unknown's avatar
ndb -  
unknown committed
588 589
  fprintf(m_errstream, "Error line %d: %s\n",
	  m_lineno, buf);
590 591 592 593 594 595 596 597 598 599 600

  //m_currentSection->print();
}

void
InitConfigFileParser::Context::reportWarning(const char * fmt, ...){
  va_list ap;
  char buf[1000];
  
  va_start(ap, fmt);
  if (fmt != 0)
601
    BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
602
  va_end(ap);
unknown's avatar
ndb -  
unknown committed
603 604
  fprintf(m_errstream, "Warning line %d: %s\n",
	  m_lineno, buf);
605
}
unknown's avatar
unknown committed
606 607 608 609 610 611 612 613 614

#include <my_sys.h>
#include <my_getopt.h>

static int order = 1;
static 
my_bool 
parse_mycnf_opt(int, const struct my_option * opt, char * value)
{
unknown's avatar
unknown committed
615
  long *app_type= (long*) &opt->app_type;
unknown's avatar
unknown committed
616
  if(opt->comment)
unknown's avatar
unknown committed
617
    (*app_type)++;
unknown's avatar
unknown committed
618
  else
unknown's avatar
unknown committed
619
    *app_type = order++;
unknown's avatar
unknown committed
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
  return 0;
}

bool
InitConfigFileParser::store_in_properties(Vector<struct my_option>& options, 
					  InitConfigFileParser::Context& ctx,
					  const char * name)
{
  for(unsigned i = 0; i<options.size(); i++)
  {
    if(options[i].comment && 
       options[i].app_type && 
       strcmp(options[i].comment, name) == 0)
    {
      Uint64 value_int;
      switch(options[i].var_type){
      case GET_INT:
	value_int = *(Uint32*)options[i].value;
	break;
      case GET_LL:
	value_int = *(Uint64*)options[i].value;
	break;
      case GET_STR:
643
	ctx.m_currentSection->put(options[i].name, *(char**)options[i].value);
unknown's avatar
unknown committed
644 645 646 647 648 649 650 651 652 653 654 655 656 657
	continue;
      default:
	abort();
      }

      const char * fname = options[i].name;
      if (!m_info->verify(ctx.m_currentInfo, fname, value_int)) {
	ctx.reportError("Illegal value %lld for parameter %s.\n"
			"Legal values are between %Lu and %Lu", 
			value_int, fname,
			m_info->getMin(ctx.m_currentInfo, fname), 
			m_info->getMax(ctx.m_currentInfo, fname));
	return false;
      }
658 659 660 661 662 663 664 665 666 667 668 669

      ConfigInfo::Status status = m_info->getStatus(ctx.m_currentInfo, fname);
      if (status == ConfigInfo::CI_DEPRICATED) {
	const char * desc = m_info->getDescription(ctx.m_currentInfo, fname);
	if(desc && desc[0]){
	  ctx.reportWarning("[%s] %s is depricated, use %s instead", 
			    ctx.fname, fname, desc);
	} else if (desc == 0){
	  ctx.reportWarning("[%s] %s is depricated", ctx.fname, fname);
	} 
      }
      
unknown's avatar
unknown committed
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
      if (options[i].var_type == GET_INT)
	ctx.m_currentSection->put(options[i].name, (Uint32)value_int);
      else
	ctx.m_currentSection->put(options[i].name, value_int);	
    }
  }
  return true;
}

bool
InitConfigFileParser::handle_mycnf_defaults(Vector<struct my_option>& options,
					    InitConfigFileParser::Context& ctx, 
					    const char * name)
{
  strcpy(ctx.fname, name);
  ctx.type = InitConfigFileParser::DefaultSection;
  ctx.m_currentSection = new Properties(true);
  ctx.m_userDefaults   = NULL;
  require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0);
  require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0);
  if(store_in_properties(options, ctx, name))
    return storeSection(ctx);
  return false;
}

static
int
load_defaults(Vector<struct my_option>& options, const char* groups[])
{
  int argc = 1;
  const char * argv[] = { "ndb_mgmd", 0, 0, 0, 0 };
  BaseString file;
  BaseString extra_file;
  BaseString group_suffix;

705 706 707
  const char *save_file = my_defaults_file;
  char *save_extra_file = my_defaults_extra_file;
  const char *save_group_suffix = my_defaults_group_suffix;
unknown's avatar
unknown committed
708

709
  if (my_defaults_file)
unknown's avatar
unknown committed
710
  {
711
    file.assfmt("--defaults-file=%s", my_defaults_file);
unknown's avatar
unknown committed
712 713 714
    argv[argc++] = file.c_str();
  }

715
  if (my_defaults_extra_file)
unknown's avatar
unknown committed
716
  {
717
    extra_file.assfmt("--defaults-extra-file=%s", my_defaults_extra_file);
unknown's avatar
unknown committed
718 719 720
    argv[argc++] = extra_file.c_str();
  }

721
  if (my_defaults_group_suffix)
unknown's avatar
unknown committed
722
  {
723 724
    group_suffix.assfmt("--defaults-group-suffix=%s",
                        my_defaults_group_suffix);
unknown's avatar
unknown committed
725 726 727 728 729 730
    argv[argc++] = group_suffix.c_str();
  }

  char ** tmp = (char**)argv;
  int ret = load_defaults("my", groups, &argc, &tmp);
  
731 732 733
  my_defaults_file = save_file;
  my_defaults_extra_file = save_extra_file;
  my_defaults_group_suffix = save_group_suffix;
unknown's avatar
unknown committed
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
  
  if (ret == 0)
  {
    return handle_options(&argc, &tmp, options.getBase(), parse_mycnf_opt);
  }
  
  return ret;
}

bool
InitConfigFileParser::load_mycnf_groups(Vector<struct my_option> & options,
					InitConfigFileParser::Context& ctx,
					const char * name,
					const char *groups[])
{
  unsigned i;
  Vector<struct my_option> copy;
  for(i = 0; i<options.size(); i++)
  {
    if(options[i].comment && strcmp(options[i].comment, name) == 0)
    {
      options[i].app_type = 0;
      copy.push_back(options[i]);
    }
  }

  struct my_option end;
  bzero(&end, sizeof(end));
  copy.push_back(end);

  if (load_defaults(copy, groups))
    return false;
  
  return store_in_properties(copy, ctx, name);
}

Config *
InitConfigFileParser::parse_mycnf() 
{
  int i;
  Config * res = 0;
  Vector<struct my_option> options;
  for(i = 0; i<ConfigInfo::m_NoOfParams; i++)
  {
    {
      struct my_option opt;
      bzero(&opt, sizeof(opt));
      const ConfigInfo::ParamInfo& param = ConfigInfo::m_ParamInfo[i];
      switch(param._type){
      case ConfigInfo::CI_BOOL:
	opt.value = (gptr*)malloc(sizeof(int));
	opt.var_type = GET_INT;
	break;
      case ConfigInfo::CI_INT: 
	opt.value = (gptr*)malloc(sizeof(int));
	opt.var_type = GET_INT;
	break;
      case ConfigInfo::CI_INT64:
	opt.value = (gptr*)malloc(sizeof(Int64));
	opt.var_type = GET_LL;
	break;
      case ConfigInfo::CI_STRING: 
	opt.value = (gptr*)malloc(sizeof(char *));
	opt.var_type = GET_STR;
	break;
      default:
	continue;
      }
      opt.name = param._fname;
      opt.id = 256;
      opt.app_type = 0;
      opt.arg_type = REQUIRED_ARG;
      opt.comment = param._section;
      options.push_back(opt);
    }
  }
  
  struct my_option *ndbd, *ndb_mgmd, *mysqld, *api;

  /**
   * Add ndbd, ndb_mgmd, api/mysqld
   */
816
  Uint32 idx = options.size();
unknown's avatar
unknown committed
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
  {
    struct my_option opt;
    bzero(&opt, sizeof(opt));
    opt.name = "ndbd";
    opt.id = 256;
    opt.value = (gptr*)malloc(sizeof(char*));
    opt.var_type = GET_STR;
    opt.arg_type = REQUIRED_ARG;
    options.push_back(opt);

    opt.name = "ndb_mgmd";
    opt.id = 256;
    opt.value = (gptr*)malloc(sizeof(char*));
    opt.var_type = GET_STR;
    opt.arg_type = REQUIRED_ARG;
    options.push_back(opt);

    opt.name = "mysqld";
    opt.id = 256;
    opt.value = (gptr*)malloc(sizeof(char*));
    opt.var_type = GET_STR;
    opt.arg_type = REQUIRED_ARG;
    options.push_back(opt);

unknown's avatar
unknown committed
841
    opt.name = "ndbapi";
unknown's avatar
unknown committed
842 843 844 845 846 847 848 849
    opt.id = 256;
    opt.value = (gptr*)malloc(sizeof(char*));
    opt.var_type = GET_STR;
    opt.arg_type = REQUIRED_ARG;
    options.push_back(opt);

    bzero(&opt, sizeof(opt));
    options.push_back(opt);
850 851 852 853 854

    ndbd = &options[idx];
    ndb_mgmd = &options[idx+1];
    mysqld = &options[idx+2];
    api = &options[idx+3];
unknown's avatar
unknown committed
855 856
  }
  
unknown's avatar
unknown committed
857
  Context ctx(m_info, m_errstream); 
unknown's avatar
unknown committed
858 859 860 861 862 863 864 865 866 867 868
  const char *groups[]= { "cluster_config", 0 };
  if (load_defaults(options, groups))
    goto end;

  ctx.m_lineno = 0;
  if(!handle_mycnf_defaults(options, ctx, "DB"))
    goto end;
  if(!handle_mycnf_defaults(options, ctx, "API"))
    goto end;
  if(!handle_mycnf_defaults(options, ctx, "MGM"))
    goto end;
869 870 871 872 873 874
  if(!handle_mycnf_defaults(options, ctx, "TCP"))
    goto end;
  if(!handle_mycnf_defaults(options, ctx, "SHM"))
    goto end;
  if(!handle_mycnf_defaults(options, ctx, "SCI"))
    goto end;
unknown's avatar
unknown committed
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951

  {
    struct sect { struct my_option* src; const char * name; } sections[] = 
      {
	{ ndb_mgmd, "MGM" }
	,{ ndbd, "DB" }
	,{ mysqld, "API" }
	,{ api, "API" }
	,{ 0, 0 }, { 0, 0 }
      };
    
    for(i = 0; sections[i].src; i++)
    {
      for(int j = i + 1; sections[j].src; j++)
      {
	if (sections[j].src->app_type < sections[i].src->app_type)
	{
	  sect swap = sections[i];
	  sections[i] = sections[j];
	  sections[j] = swap;
	}
      }
    }
    
    ctx.type = InitConfigFileParser::Section;
    ctx.m_sectionLineno  = ctx.m_lineno;      
    for(i = 0; sections[i].src; i++)
    {
      if (sections[i].src->app_type)
      {
	strcpy(ctx.fname, sections[i].name);
	BaseString str(*(char**)sections[i].src->value);
	Vector<BaseString> list;
	str.split(list, ",");
	
	const char * defaults_groups[] = { 0,  0, 0 };
	for(unsigned j = 0; j<list.size(); j++)
	{
	  BaseString group_idx;
	  BaseString group_host;
	  group_idx.assfmt("%s.%s.%d", groups[0], 
			   sections[i].src->name, j + 1);
	  group_host.assfmt("%s.%s.%s", groups[0], 
			    sections[i].src->name, list[j].c_str());
	  defaults_groups[0] = group_idx.c_str();
	  if(list[j].length())
	    defaults_groups[1] = group_host.c_str();
	  else
	    defaults_groups[1] = 0;
	  
	  ctx.m_currentSection = new Properties(true);
	  ctx.m_userDefaults = getSection(ctx.fname, ctx.m_defaults);
	  require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0);
	  require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname))!= 0);
	  ctx.m_currentSection->put("HostName", list[j].c_str());
	  if(!load_mycnf_groups(options, ctx, sections[i].name, 
				defaults_groups))
	    goto end;
	  
	  if(!storeSection(ctx))
	    goto end;
	}
      }
    }
  }

  res = run_config_rules(ctx);

end:
  for(i = 0; options[i].name; i++)
    free(options[i].value);

  return res;
}

template class Vector<struct my_option>;

unknown's avatar
unknown committed
952 953 954
/*
  See include/my_getopt.h for the declaration of struct my_option
*/