00001 /* Copyright (C) 2003 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 #include <ndb_global.h> 00018 00019 #include "InitConfigFileParser.hpp" 00020 #include "Config.hpp" 00021 #include "MgmtErrorReporter.hpp" 00022 #include <NdbOut.hpp> 00023 #include "ConfigInfo.hpp" 00024 #include <m_string.h> 00025 00026 const int MAX_LINE_LENGTH = 1024; // Max length of line of text in config file 00027 static void trim(char *); 00028 00029 static void require(bool v) { if(!v) abort();} 00030 00031 //**************************************************************************** 00032 // Ctor / Dtor 00033 //**************************************************************************** 00034 InitConfigFileParser::InitConfigFileParser(FILE * out) 00035 { 00036 m_info = new ConfigInfo(); 00037 m_errstream = out ? out : stdout; 00038 } 00039 00040 InitConfigFileParser::~InitConfigFileParser() { 00041 delete m_info; 00042 } 00043 00044 //**************************************************************************** 00045 // Read Config File 00046 //**************************************************************************** 00047 InitConfigFileParser::Context::Context(const ConfigInfo * info, FILE * out) 00048 : m_userProperties(true), m_configValues(1000, 20) { 00049 00050 m_config = new Properties(true); 00051 m_defaults = new Properties(true); 00052 m_errstream = out; 00053 } 00054 00055 InitConfigFileParser::Context::~Context(){ 00056 if(m_config != 0) 00057 delete m_config; 00058 00059 if(m_defaults != 0) 00060 delete m_defaults; 00061 } 00062 00063 Config * 00064 InitConfigFileParser::parseConfig(const char * filename) { 00065 FILE * file = fopen(filename, "r"); 00066 if(file == 0){ 00067 fprintf(m_errstream, "Error opening file: %s\n", filename); 00068 return 0; 00069 } 00070 00071 Config * ret = parseConfig(file); 00072 fclose(file); 00073 return ret; 00074 } 00075 00076 Config * 00077 InitConfigFileParser::parseConfig(FILE * file) { 00078 00079 char line[MAX_LINE_LENGTH]; 00080 00081 Context ctx(m_info, m_errstream); 00082 ctx.m_lineno = 0; 00083 ctx.m_currentSection = 0; 00084 00085 /************* 00086 * Open file * 00087 *************/ 00088 if (file == NULL) { 00089 return 0; 00090 } 00091 00092 /*********************** 00093 * While lines to read * 00094 ***********************/ 00095 while (fgets(line, MAX_LINE_LENGTH, file)) { 00096 ctx.m_lineno++; 00097 00098 trim(line); 00099 00100 if (isEmptyLine(line)) // Skip if line is empty or comment 00101 continue; 00102 00103 // End with NULL instead of newline 00104 if (line[strlen(line)-1] == '\n') 00105 line[strlen(line)-1] = '\0'; 00106 00107 /******************************** 00108 * 1. Parse new default section * 00109 ********************************/ 00110 if (char* section = parseDefaultSectionHeader(line)) { 00111 if(!storeSection(ctx)){ 00112 free(section); 00113 ctx.reportError("Could not store previous default section " 00114 "of configuration file."); 00115 return 0; 00116 } 00117 BaseString::snprintf(ctx.fname, sizeof(ctx.fname), section); free(section); 00118 ctx.type = InitConfigFileParser::DefaultSection; 00119 ctx.m_sectionLineno = ctx.m_lineno; 00120 ctx.m_currentSection = new Properties(true); 00121 ctx.m_userDefaults = NULL; 00122 require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0); 00123 require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0); 00124 continue; 00125 } 00126 00127 /************************ 00128 * 2. Parse new section * 00129 ************************/ 00130 if (char* section = parseSectionHeader(line)) { 00131 if(!storeSection(ctx)){ 00132 free(section); 00133 ctx.reportError("Could not store previous section " 00134 "of configuration file."); 00135 return 0; 00136 } 00137 BaseString::snprintf(ctx.fname, sizeof(ctx.fname), section); 00138 free(section); 00139 ctx.type = InitConfigFileParser::Section; 00140 ctx.m_sectionLineno = ctx.m_lineno; 00141 ctx.m_currentSection = new Properties(true); 00142 ctx.m_userDefaults = getSection(ctx.fname, ctx.m_defaults); 00143 require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0); 00144 require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0); 00145 continue; 00146 } 00147 00148 /**************************** 00149 * 3. Parse name-value pair * 00150 ****************************/ 00151 if (!parseNameValuePair(ctx, line)) { 00152 ctx.reportError("Could not parse name-value pair in config file."); 00153 return 0; 00154 } 00155 } 00156 00157 if (ferror(file)){ 00158 ctx.reportError("Failure in reading"); 00159 return 0; 00160 } 00161 00162 if(!storeSection(ctx)) { 00163 ctx.reportError("Could not store section of configuration file."); 00164 return 0; 00165 } 00166 00167 return run_config_rules(ctx); 00168 } 00169 00170 Config* 00171 InitConfigFileParser::run_config_rules(Context& ctx) 00172 { 00173 for(size_t i = 0; ConfigInfo::m_ConfigRules[i].m_configRule != 0; i++){ 00174 ctx.type = InitConfigFileParser::Undefined; 00175 ctx.m_currentSection = 0; 00176 ctx.m_userDefaults = 0; 00177 ctx.m_currentInfo = 0; 00178 ctx.m_systemDefaults = 0; 00179 00180 Vector<ConfigInfo::ConfigRuleSection> tmp; 00181 if(!(* ConfigInfo::m_ConfigRules[i].m_configRule)(tmp, ctx, 00182 ConfigInfo::m_ConfigRules[i].m_ruleData)) 00183 return 0; 00184 00185 for(size_t j = 0; j<tmp.size(); j++){ 00186 BaseString::snprintf(ctx.fname, sizeof(ctx.fname), tmp[j].m_sectionType.c_str()); 00187 ctx.type = InitConfigFileParser::Section; 00188 ctx.m_currentSection = tmp[j].m_sectionData; 00189 ctx.m_userDefaults = getSection(ctx.fname, ctx.m_defaults); 00190 require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0); 00191 require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0); 00192 if(!storeSection(ctx)) 00193 return 0; 00194 } 00195 } 00196 00197 Uint32 nConnections = 0; 00198 Uint32 nComputers = 0; 00199 Uint32 nNodes = 0; 00200 Uint32 nExtConnections = 0; 00201 const char * system = "?"; 00202 ctx.m_userProperties.get("NoOfConnections", &nConnections); 00203 ctx.m_userProperties.get("NoOfComputers", &nComputers); 00204 ctx.m_userProperties.get("NoOfNodes", &nNodes); 00205 ctx.m_userProperties.get("ExtNoOfConnections", &nExtConnections); 00206 ctx.m_userProperties.get("ExtSystem", &system); 00207 ctx.m_config->put("NoOfConnections", nConnections); 00208 ctx.m_config->put("NoOfComputers", nComputers); 00209 ctx.m_config->put("NoOfNodes", nNodes); 00210 00211 char tmpLine[MAX_LINE_LENGTH]; 00212 BaseString::snprintf(tmpLine, MAX_LINE_LENGTH, "EXTERNAL SYSTEM_"); 00213 strncat(tmpLine, system, MAX_LINE_LENGTH); 00214 strncat(tmpLine, ":NoOfConnections", MAX_LINE_LENGTH); 00215 ctx.m_config->put(tmpLine, nExtConnections); 00216 00217 Config * ret = new Config(); 00218 ret->m_configValues = (struct ndb_mgm_configuration*)ctx.m_configValues.getConfigValues(); 00219 ret->m_oldConfig = ctx.m_config; ctx.m_config = 0; 00220 return ret; 00221 } 00222 00223 //**************************************************************************** 00224 // Parse Name-Value Pair 00225 //**************************************************************************** 00226 00227 bool InitConfigFileParser::parseNameValuePair(Context& ctx, const char* line) 00228 { 00229 if (ctx.m_currentSection == NULL){ 00230 ctx.reportError("Value specified outside section"); 00231 return false; 00232 } 00233 00234 // ************************************* 00235 // Split string at first occurrence of 00236 // '=' or ':' 00237 // ************************************* 00238 00239 Vector<BaseString> tmp_string_split; 00240 if (BaseString(line).split(tmp_string_split, 00241 "=:", 2) != 2) 00242 { 00243 ctx.reportError("Parse error"); 00244 return false; 00245 } 00246 00247 // ************************************* 00248 // Remove all after # 00249 // ************************************* 00250 00251 Vector<BaseString> tmp_string_split2; 00252 tmp_string_split[1].split(tmp_string_split2, 00253 "#", 2); 00254 tmp_string_split[1]=tmp_string_split2[0]; 00255 00256 // ************************************* 00257 // Remove leading and trailing chars 00258 // ************************************* 00259 { 00260 for (int i = 0; i < 2; i++) 00261 tmp_string_split[i].trim("\r\n \t"); 00262 } 00263 00264 // ************************************* 00265 // First in split is fname 00266 // ************************************* 00267 00268 const char *fname= tmp_string_split[0].c_str(); 00269 00270 if (!ctx.m_currentInfo->contains(fname)) { 00271 ctx.reportError("[%s] Unknown parameter: %s", ctx.fname, fname); 00272 return false; 00273 } 00274 ConfigInfo::Status status = m_info->getStatus(ctx.m_currentInfo, fname); 00275 if (status == ConfigInfo::CI_NOTIMPLEMENTED) { 00276 ctx.reportWarning("[%s] %s not yet implemented", ctx.fname, fname); 00277 } 00278 if (status == ConfigInfo::CI_DEPRICATED) { 00279 const char * desc = m_info->getDescription(ctx.m_currentInfo, fname); 00280 if(desc && desc[0]){ 00281 ctx.reportWarning("[%s] %s is depricated, use %s instead", 00282 ctx.fname, fname, desc); 00283 } else if (desc == 0){ 00284 ctx.reportWarning("[%s] %s is depricated", ctx.fname, fname); 00285 } 00286 } 00287 00288 // *********************** 00289 // Store name-value pair 00290 // *********************** 00291 00292 return storeNameValuePair(ctx, fname, tmp_string_split[1].c_str()); 00293 } 00294 00295 00296 //**************************************************************************** 00297 // STORE NAME-VALUE pair in properties section 00298 //**************************************************************************** 00299 00300 bool 00301 InitConfigFileParser::storeNameValuePair(Context& ctx, 00302 const char* fname, 00303 const char* value) { 00304 00305 const char * pname = fname; 00306 00307 if (ctx.m_currentSection->contains(pname)) { 00308 ctx.reportError("[%s] Parameter %s specified twice", ctx.fname, fname); 00309 return false; 00310 } 00311 00312 // *********************** 00313 // Store name-value pair 00314 // *********************** 00315 00316 const ConfigInfo::Type type = m_info->getType(ctx.m_currentInfo, fname); 00317 switch(type){ 00318 case ConfigInfo::CI_BOOL: { 00319 bool value_bool; 00320 if (!convertStringToBool(value, value_bool)) { 00321 ctx.reportError("Illegal boolean value for parameter %s", fname); 00322 return false; 00323 } 00324 MGM_REQUIRE(ctx.m_currentSection->put(pname, value_bool)); 00325 break; 00326 } 00327 case ConfigInfo::CI_INT: 00328 case ConfigInfo::CI_INT64:{ 00329 Uint64 value_int; 00330 if (!convertStringToUint64(value, value_int)) { 00331 ctx.reportError("Illegal integer value for parameter %s", fname); 00332 return false; 00333 } 00334 if (!m_info->verify(ctx.m_currentInfo, fname, value_int)) { 00335 ctx.reportError("Illegal value %s for parameter %s.\n" 00336 "Legal values are between %Lu and %Lu", value, fname, 00337 m_info->getMin(ctx.m_currentInfo, fname), 00338 m_info->getMax(ctx.m_currentInfo, fname)); 00339 return false; 00340 } 00341 if(type == ConfigInfo::CI_INT){ 00342 MGM_REQUIRE(ctx.m_currentSection->put(pname, (Uint32)value_int)); 00343 } else { 00344 MGM_REQUIRE(ctx.m_currentSection->put64(pname, value_int)); 00345 } 00346 break; 00347 } 00348 case ConfigInfo::CI_STRING: 00349 MGM_REQUIRE(ctx.m_currentSection->put(pname, value)); 00350 break; 00351 case ConfigInfo::CI_SECTION: 00352 abort(); 00353 } 00354 return true; 00355 } 00356 00357 //**************************************************************************** 00358 // Is Empty Line 00359 //**************************************************************************** 00360 00361 bool InitConfigFileParser::isEmptyLine(const char* line) const { 00362 int i; 00363 00364 // Check if it is a comment line 00365 if (line[0] == '#') return true; 00366 00367 // Check if it is a line with only spaces 00368 for (i = 0; i < MAX_LINE_LENGTH && line[i] != '\n' && line[i] != '\0'; i++) { 00369 if (line[i] != ' ' && line[i] != '\t') return false; 00370 } 00371 return true; 00372 } 00373 00374 //**************************************************************************** 00375 // Convert String to Int 00376 //**************************************************************************** 00377 bool InitConfigFileParser::convertStringToUint64(const char* s, 00378 Uint64& val, 00379 Uint32 log10base) { 00380 if (s == NULL) 00381 return false; 00382 if (strlen(s) == 0) 00383 return false; 00384 00385 errno = 0; 00386 char* p; 00387 Int64 v = strtoll(s, &p, log10base); 00388 if (errno != 0) 00389 return false; 00390 00391 long mul = 0; 00392 if (p != &s[strlen(s)]){ 00393 char * tmp = strdup(p); 00394 trim(tmp); 00395 switch(tmp[0]){ 00396 case 'k': 00397 case 'K': 00398 mul = 10; 00399 break; 00400 case 'M': 00401 mul = 20; 00402 break; 00403 case 'G': 00404 mul = 30; 00405 break; 00406 default: 00407 free(tmp); 00408 return false; 00409 } 00410 free(tmp); 00411 } 00412 00413 val = (v << mul); 00414 return true; 00415 } 00416 00417 bool InitConfigFileParser::convertStringToBool(const char* s, bool& val) { 00418 if (s == NULL) return false; 00419 if (strlen(s) == 0) return false; 00420 00421 if (!strcmp(s, "Y") || !strcmp(s, "y") || 00422 !strcmp(s, "Yes") || !strcmp(s, "YES") || !strcmp(s, "yes") || 00423 !strcmp(s, "True") || !strcmp(s, "TRUE") || !strcmp(s, "true") || 00424 !strcmp(s, "1")) { 00425 val = true; 00426 return true; 00427 } 00428 00429 if (!strcmp(s, "N") || !strcmp(s, "n") || 00430 !strcmp(s, "No") || !strcmp(s, "NO") || !strcmp(s, "no") || 00431 !strcmp(s, "False") || !strcmp(s, "FALSE") || !strcmp(s, "false") || 00432 !strcmp(s, "0")) { 00433 val = false; 00434 return true; 00435 } 00436 00437 return false; // Failure to convert 00438 } 00439 00440 //**************************************************************************** 00441 // Parse Section Header 00442 //**************************************************************************** 00443 static void 00444 trim(char * str){ 00445 int len = strlen(str); 00446 for(len--; 00447 (str[len] == '\r' || str[len] == '\n' || 00448 str[len] == ' ' || str[len] == '\t') && 00449 len > 0; 00450 len--) 00451 str[len] = 0; 00452 00453 int pos = 0; 00454 while(str[pos] == ' ' || str[pos] == '\t') 00455 pos++; 00456 00457 if(str[pos] == '\"' && str[len] == '\"') { 00458 pos++; 00459 str[len] = 0; 00460 len--; 00461 } 00462 00463 memmove(str, &str[pos], len - pos + 2); 00464 } 00465 00466 char* 00467 InitConfigFileParser::parseSectionHeader(const char* line) const { 00468 char * tmp = strdup(line); 00469 00470 if(tmp[0] != '['){ 00471 free(tmp); 00472 return NULL; 00473 } 00474 00475 if(tmp[strlen(tmp)-1] != ']'){ 00476 free(tmp); 00477 return NULL; 00478 } 00479 tmp[strlen(tmp)-1] = 0; 00480 00481 tmp[0] = ' '; 00482 trim(tmp); 00483 00484 // Get the correct header name if an alias 00485 { 00486 const char *tmp_alias= m_info->getAlias(tmp); 00487 if (tmp_alias) { 00488 free(tmp); 00489 tmp= strdup(tmp_alias); 00490 } 00491 } 00492 00493 // Lookup token among sections 00494 if(!m_info->isSection(tmp)) { 00495 free(tmp); 00496 return NULL; 00497 } 00498 if(m_info->getInfo(tmp)) return tmp; 00499 00500 free(tmp); 00501 return NULL; 00502 } 00503 00504 //**************************************************************************** 00505 // Parse Default Section Header 00506 //**************************************************************************** 00507 00508 char* 00509 InitConfigFileParser::parseDefaultSectionHeader(const char* line) const { 00510 static char token1[MAX_LINE_LENGTH], token2[MAX_LINE_LENGTH]; 00511 00512 int no = sscanf(line, "[%120[A-Z_a-z] %120[A-Z_a-z]]", token1, token2); 00513 00514 // Not correct no of tokens 00515 if (no != 2) return NULL; 00516 00517 // Not correct keyword at end 00518 if (!strcasecmp(token2, "DEFAULT") == 0) return NULL; 00519 00520 const char *token1_alias= m_info->getAlias(token1); 00521 if (token1_alias == 0) 00522 token1_alias= token1; 00523 00524 if(m_info->getInfo(token1_alias)){ 00525 return strdup(token1_alias); 00526 } 00527 00528 // Did not find section 00529 return NULL; 00530 } 00531 00532 const Properties * 00533 InitConfigFileParser::getSection(const char * name, const Properties * src){ 00534 const Properties * p; 00535 if(src && src->get(name, &p)) 00536 return p; 00537 00538 return 0; 00539 } 00540 00541 //**************************************************************************** 00542 // STORE section 00543 //**************************************************************************** 00544 bool 00545 InitConfigFileParser::storeSection(Context& ctx){ 00546 if(ctx.m_currentSection == NULL) 00547 return true; 00548 for(int i = strlen(ctx.fname) - 1; i>=0; i--){ 00549 ctx.fname[i] = toupper(ctx.fname[i]); 00550 } 00551 BaseString::snprintf(ctx.pname, sizeof(ctx.pname), ctx.fname); 00552 char buf[255]; 00553 if(ctx.type == InitConfigFileParser::Section) 00554 BaseString::snprintf(buf, sizeof(buf), "%s", ctx.fname); 00555 if(ctx.type == InitConfigFileParser::DefaultSection) 00556 BaseString::snprintf(buf, sizeof(buf), "%s DEFAULT", ctx.fname); 00557 BaseString::snprintf(ctx.fname, sizeof(ctx.fname), buf); 00558 if(ctx.type == InitConfigFileParser::Section){ 00559 for(int i = 0; i<m_info->m_NoOfRules; i++){ 00560 const ConfigInfo::SectionRule & rule = m_info->m_SectionRules[i]; 00561 if(!strcmp(rule.m_section, "*") || !strcmp(rule.m_section, ctx.fname)){ 00562 if(!(* rule.m_sectionRule)(ctx, rule.m_ruleData)){ 00563 return false; 00564 } 00565 } 00566 } 00567 } 00568 if(ctx.type == InitConfigFileParser::DefaultSection && 00569 !ctx.m_defaults->put(ctx.pname, ctx.m_currentSection)) 00570 { 00571 ctx.reportError("Duplicate default section not allowed"); 00572 return false; 00573 } 00574 if(ctx.type == InitConfigFileParser::Section) 00575 require(ctx.m_config->put(ctx.pname, ctx.m_currentSection)); 00576 delete ctx.m_currentSection; ctx.m_currentSection = NULL; 00577 return true; 00578 } 00579 00580 void 00581 InitConfigFileParser::Context::reportError(const char * fmt, ...){ 00582 va_list ap; 00583 char buf[1000]; 00584 00585 va_start(ap, fmt); 00586 if (fmt != 0) 00587 BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); 00588 va_end(ap); 00589 fprintf(m_errstream, "Error line %d: %s\n", 00590 m_lineno, buf); 00591 00592 //m_currentSection->print(); 00593 } 00594 00595 void 00596 InitConfigFileParser::Context::reportWarning(const char * fmt, ...){ 00597 va_list ap; 00598 char buf[1000]; 00599 00600 va_start(ap, fmt); 00601 if (fmt != 0) 00602 BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap); 00603 va_end(ap); 00604 fprintf(m_errstream, "Warning line %d: %s\n", 00605 m_lineno, buf); 00606 } 00607 00608 #include <my_sys.h> 00609 #include <my_getopt.h> 00610 00611 static int order = 1; 00612 static 00613 my_bool 00614 parse_mycnf_opt(int, const struct my_option * opt, char * value) 00615 { 00616 if(opt->comment) 00617 ((struct my_option *)opt)->app_type++; 00618 else 00619 ((struct my_option *)opt)->app_type = order++; 00620 return 0; 00621 } 00622 00623 bool 00624 InitConfigFileParser::store_in_properties(Vector<struct my_option>& options, 00625 InitConfigFileParser::Context& ctx, 00626 const char * name) 00627 { 00628 for(unsigned i = 0; i<options.size(); i++) 00629 { 00630 if(options[i].comment && 00631 options[i].app_type && 00632 strcmp(options[i].comment, name) == 0) 00633 { 00634 Uint64 value_int; 00635 switch(options[i].var_type){ 00636 case GET_INT: 00637 value_int = *(Uint32*)options[i].value; 00638 break; 00639 case GET_LL: 00640 value_int = *(Uint64*)options[i].value; 00641 break; 00642 case GET_STR: 00643 ctx.m_currentSection->put(options[i].name, *(char**)options[i].value); 00644 continue; 00645 default: 00646 abort(); 00647 } 00648 00649 const char * fname = options[i].name; 00650 if (!m_info->verify(ctx.m_currentInfo, fname, value_int)) { 00651 ctx.reportError("Illegal value %lld for parameter %s.\n" 00652 "Legal values are between %Lu and %Lu", 00653 value_int, fname, 00654 m_info->getMin(ctx.m_currentInfo, fname), 00655 m_info->getMax(ctx.m_currentInfo, fname)); 00656 return false; 00657 } 00658 if (options[i].var_type == GET_INT) 00659 ctx.m_currentSection->put(options[i].name, (Uint32)value_int); 00660 else 00661 ctx.m_currentSection->put(options[i].name, value_int); 00662 } 00663 } 00664 return true; 00665 } 00666 00667 bool 00668 InitConfigFileParser::handle_mycnf_defaults(Vector<struct my_option>& options, 00669 InitConfigFileParser::Context& ctx, 00670 const char * name) 00671 { 00672 strcpy(ctx.fname, name); 00673 ctx.type = InitConfigFileParser::DefaultSection; 00674 ctx.m_currentSection = new Properties(true); 00675 ctx.m_userDefaults = NULL; 00676 require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0); 00677 require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0); 00678 if(store_in_properties(options, ctx, name)) 00679 return storeSection(ctx); 00680 return false; 00681 } 00682 00683 static 00684 int 00685 load_defaults(Vector<struct my_option>& options, const char* groups[]) 00686 { 00687 int argc = 1; 00688 const char * argv[] = { "ndb_mgmd", 0, 0, 0, 0 }; 00689 BaseString file; 00690 BaseString extra_file; 00691 BaseString group_suffix; 00692 00693 const char *save_file = defaults_file; 00694 char *save_extra_file = defaults_extra_file; 00695 const char *save_group_suffix = defaults_group_suffix; 00696 00697 if (defaults_file) 00698 { 00699 file.assfmt("--defaults-file=%s", defaults_file); 00700 argv[argc++] = file.c_str(); 00701 } 00702 00703 if (defaults_extra_file) 00704 { 00705 extra_file.assfmt("--defaults-extra-file=%s", defaults_extra_file); 00706 argv[argc++] = extra_file.c_str(); 00707 } 00708 00709 if (defaults_group_suffix) 00710 { 00711 group_suffix.assfmt("--defaults-group-suffix=%s", defaults_group_suffix); 00712 argv[argc++] = group_suffix.c_str(); 00713 } 00714 00715 char ** tmp = (char**)argv; 00716 int ret = load_defaults("my", groups, &argc, &tmp); 00717 00718 defaults_file = save_file; 00719 defaults_extra_file = save_extra_file; 00720 defaults_group_suffix = save_group_suffix; 00721 00722 if (ret == 0) 00723 { 00724 return handle_options(&argc, &tmp, options.getBase(), parse_mycnf_opt); 00725 } 00726 00727 return ret; 00728 } 00729 00730 bool 00731 InitConfigFileParser::load_mycnf_groups(Vector<struct my_option> & options, 00732 InitConfigFileParser::Context& ctx, 00733 const char * name, 00734 const char *groups[]) 00735 { 00736 unsigned i; 00737 Vector<struct my_option> copy; 00738 for(i = 0; i<options.size(); i++) 00739 { 00740 if(options[i].comment && strcmp(options[i].comment, name) == 0) 00741 { 00742 options[i].app_type = 0; 00743 copy.push_back(options[i]); 00744 } 00745 } 00746 00747 struct my_option end; 00748 bzero(&end, sizeof(end)); 00749 copy.push_back(end); 00750 00751 if (load_defaults(copy, groups)) 00752 return false; 00753 00754 return store_in_properties(copy, ctx, name); 00755 } 00756 00757 Config * 00758 InitConfigFileParser::parse_mycnf() 00759 { 00760 int i; 00761 Config * res = 0; 00762 Vector<struct my_option> options; 00763 for(i = 0; i<ConfigInfo::m_NoOfParams; i++) 00764 { 00765 { 00766 struct my_option opt; 00767 bzero(&opt, sizeof(opt)); 00768 const ConfigInfo::ParamInfo& param = ConfigInfo::m_ParamInfo[i]; 00769 switch(param._type){ 00770 case ConfigInfo::CI_BOOL: 00771 opt.value = (gptr*)malloc(sizeof(int)); 00772 opt.var_type = GET_INT; 00773 break; 00774 case ConfigInfo::CI_INT: 00775 opt.value = (gptr*)malloc(sizeof(int)); 00776 opt.var_type = GET_INT; 00777 break; 00778 case ConfigInfo::CI_INT64: 00779 opt.value = (gptr*)malloc(sizeof(Int64)); 00780 opt.var_type = GET_LL; 00781 break; 00782 case ConfigInfo::CI_STRING: 00783 opt.value = (gptr*)malloc(sizeof(char *)); 00784 opt.var_type = GET_STR; 00785 break; 00786 default: 00787 continue; 00788 } 00789 opt.name = param._fname; 00790 opt.id = 256; 00791 opt.app_type = 0; 00792 opt.arg_type = REQUIRED_ARG; 00793 opt.comment = param._section; 00794 options.push_back(opt); 00795 } 00796 } 00797 00798 struct my_option *ndbd, *ndb_mgmd, *mysqld, *api; 00799 00803 Uint32 idx = options.size(); 00804 { 00805 struct my_option opt; 00806 bzero(&opt, sizeof(opt)); 00807 opt.name = "ndbd"; 00808 opt.id = 256; 00809 opt.value = (gptr*)malloc(sizeof(char*)); 00810 opt.var_type = GET_STR; 00811 opt.arg_type = REQUIRED_ARG; 00812 options.push_back(opt); 00813 00814 opt.name = "ndb_mgmd"; 00815 opt.id = 256; 00816 opt.value = (gptr*)malloc(sizeof(char*)); 00817 opt.var_type = GET_STR; 00818 opt.arg_type = REQUIRED_ARG; 00819 options.push_back(opt); 00820 00821 opt.name = "mysqld"; 00822 opt.id = 256; 00823 opt.value = (gptr*)malloc(sizeof(char*)); 00824 opt.var_type = GET_STR; 00825 opt.arg_type = REQUIRED_ARG; 00826 options.push_back(opt); 00827 00828 opt.name = "api"; 00829 opt.id = 256; 00830 opt.value = (gptr*)malloc(sizeof(char*)); 00831 opt.var_type = GET_STR; 00832 opt.arg_type = REQUIRED_ARG; 00833 options.push_back(opt); 00834 00835 bzero(&opt, sizeof(opt)); 00836 options.push_back(opt); 00837 00838 ndbd = &options[idx]; 00839 ndb_mgmd = &options[idx+1]; 00840 mysqld = &options[idx+2]; 00841 api = &options[idx+3]; 00842 } 00843 00844 00845 Context ctx(m_info, m_errstream); 00846 const char *groups[]= { "cluster_config", 0 }; 00847 if (load_defaults(options, groups)) 00848 goto end; 00849 00850 ctx.m_lineno = 0; 00851 if(!handle_mycnf_defaults(options, ctx, "DB")) 00852 goto end; 00853 if(!handle_mycnf_defaults(options, ctx, "API")) 00854 goto end; 00855 if(!handle_mycnf_defaults(options, ctx, "MGM")) 00856 goto end; 00857 if(!handle_mycnf_defaults(options, ctx, "TCP")) 00858 goto end; 00859 if(!handle_mycnf_defaults(options, ctx, "SHM")) 00860 goto end; 00861 if(!handle_mycnf_defaults(options, ctx, "SCI")) 00862 goto end; 00863 00864 { 00865 struct sect { struct my_option* src; const char * name; } sections[] = 00866 { 00867 { ndb_mgmd, "MGM" } 00868 ,{ ndbd, "DB" } 00869 ,{ mysqld, "API" } 00870 ,{ api, "API" } 00871 ,{ 0, 0 }, { 0, 0 } 00872 }; 00873 00874 for(i = 0; sections[i].src; i++) 00875 { 00876 for(int j = i + 1; sections[j].src; j++) 00877 { 00878 if (sections[j].src->app_type < sections[i].src->app_type) 00879 { 00880 sect swap = sections[i]; 00881 sections[i] = sections[j]; 00882 sections[j] = swap; 00883 } 00884 } 00885 } 00886 00887 ctx.type = InitConfigFileParser::Section; 00888 ctx.m_sectionLineno = ctx.m_lineno; 00889 for(i = 0; sections[i].src; i++) 00890 { 00891 if (sections[i].src->app_type) 00892 { 00893 strcpy(ctx.fname, sections[i].name); 00894 BaseString str(*(char**)sections[i].src->value); 00895 Vector<BaseString> list; 00896 str.split(list, ","); 00897 00898 const char * defaults_groups[] = { 0, 0, 0 }; 00899 for(unsigned j = 0; j<list.size(); j++) 00900 { 00901 BaseString group_idx; 00902 BaseString group_host; 00903 group_idx.assfmt("%s.%s.%d", groups[0], 00904 sections[i].src->name, j + 1); 00905 group_host.assfmt("%s.%s.%s", groups[0], 00906 sections[i].src->name, list[j].c_str()); 00907 defaults_groups[0] = group_idx.c_str(); 00908 if(list[j].length()) 00909 defaults_groups[1] = group_host.c_str(); 00910 else 00911 defaults_groups[1] = 0; 00912 00913 ctx.m_currentSection = new Properties(true); 00914 ctx.m_userDefaults = getSection(ctx.fname, ctx.m_defaults); 00915 require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0); 00916 require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname))!= 0); 00917 ctx.m_currentSection->put("HostName", list[j].c_str()); 00918 if(!load_mycnf_groups(options, ctx, sections[i].name, 00919 defaults_groups)) 00920 goto end; 00921 00922 if(!storeSection(ctx)) 00923 goto end; 00924 } 00925 } 00926 } 00927 } 00928 00929 res = run_config_rules(ctx); 00930 00931 end: 00932 for(i = 0; options[i].name; i++) 00933 free(options[i].value); 00934 00935 return res; 00936 } 00937 00938 template class Vector<struct my_option>; 00939 00940 #if 0 00941 struct my_option 00942 { 00943 const char *name; /* Name of the option */ 00944 int id; /* unique id or short option */ 00945 const char *comment; /* option comment, for autom. --help */ 00946 gptr *value; /* The variable value */ 00947 gptr *u_max_value; /* The user def. max variable value */ 00948 const char **str_values; /* Pointer to possible values */ 00949 ulong var_type; 00950 enum get_opt_arg_type arg_type; 00951 longlong def_value; /* Default value */ 00952 longlong min_value; /* Min allowed value */ 00953 longlong max_value; /* Max allowed value */ 00954 longlong sub_size; /* Subtract this from given value */ 00955 long block_size; /* Value should be a mult. of this */ 00956 int app_type; /* To be used by an application */ 00957 }; 00958 #endif
1.4.7

