mirror of
https://github.com/MariaDB/server.git
synced 2025-08-09 22:24:09 +03:00
954 lines
26 KiB
C++
954 lines
26 KiB
C++
/* 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
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
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 */
|
|
|
|
#include <ndb_global.h>
|
|
|
|
#include "InitConfigFileParser.hpp"
|
|
#include "Config.hpp"
|
|
#include "MgmtErrorReporter.hpp"
|
|
#include <NdbOut.hpp>
|
|
#include "ConfigInfo.hpp"
|
|
#include <m_string.h>
|
|
|
|
const int MAX_LINE_LENGTH = 1024; // Max length of line of text in config file
|
|
static void trim(char *);
|
|
|
|
static void require(bool v) { if(!v) abort();}
|
|
|
|
//****************************************************************************
|
|
// Ctor / Dtor
|
|
//****************************************************************************
|
|
InitConfigFileParser::InitConfigFileParser(FILE * out)
|
|
{
|
|
m_info = new ConfigInfo();
|
|
m_errstream = out ? out : stdout;
|
|
}
|
|
|
|
InitConfigFileParser::~InitConfigFileParser() {
|
|
delete m_info;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// Read Config File
|
|
//****************************************************************************
|
|
InitConfigFileParser::Context::Context(const ConfigInfo * info, FILE * out)
|
|
: m_userProperties(true), m_configValues(1000, 20) {
|
|
|
|
m_config = new Properties(true);
|
|
m_defaults = new Properties(true);
|
|
m_errstream = out;
|
|
}
|
|
|
|
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){
|
|
fprintf(m_errstream, "Error opening file: %s\n", filename);
|
|
return 0;
|
|
}
|
|
|
|
Config * ret = parseConfig(file);
|
|
fclose(file);
|
|
return ret;
|
|
}
|
|
|
|
Config *
|
|
InitConfigFileParser::parseConfig(FILE * file) {
|
|
|
|
char line[MAX_LINE_LENGTH];
|
|
|
|
Context ctx(m_info, m_errstream);
|
|
ctx.m_lineno = 0;
|
|
ctx.m_currentSection = 0;
|
|
|
|
/*************
|
|
* Open file *
|
|
*************/
|
|
if (file == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
/***********************
|
|
* While lines to read *
|
|
***********************/
|
|
while (fgets(line, MAX_LINE_LENGTH, file)) {
|
|
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.");
|
|
return 0;
|
|
}
|
|
BaseString::snprintf(ctx.fname, sizeof(ctx.fname), section); free(section);
|
|
ctx.type = InitConfigFileParser::DefaultSection;
|
|
ctx.m_sectionLineno = ctx.m_lineno;
|
|
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);
|
|
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.");
|
|
return 0;
|
|
}
|
|
BaseString::snprintf(ctx.fname, sizeof(ctx.fname), section);
|
|
free(section);
|
|
ctx.type = InitConfigFileParser::Section;
|
|
ctx.m_sectionLineno = ctx.m_lineno;
|
|
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);
|
|
continue;
|
|
}
|
|
|
|
/****************************
|
|
* 3. Parse name-value pair *
|
|
****************************/
|
|
if (!parseNameValuePair(ctx, line)) {
|
|
ctx.reportError("Could not parse name-value pair in config file.");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (ferror(file)){
|
|
ctx.reportError("Failure in reading");
|
|
return 0;
|
|
}
|
|
|
|
if(!storeSection(ctx)) {
|
|
ctx.reportError("Could not store section of configuration file.");
|
|
return 0;
|
|
}
|
|
|
|
return run_config_rules(ctx);
|
|
}
|
|
|
|
Config*
|
|
InitConfigFileParser::run_config_rules(Context& ctx)
|
|
{
|
|
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++){
|
|
BaseString::snprintf(ctx.fname, sizeof(ctx.fname), tmp[j].m_sectionType.c_str());
|
|
ctx.type = InitConfigFileParser::Section;
|
|
ctx.m_currentSection = tmp[j].m_sectionData;
|
|
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);
|
|
if(!storeSection(ctx))
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
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);
|
|
ctx.m_config->put("NoOfConnections", nConnections);
|
|
ctx.m_config->put("NoOfComputers", nComputers);
|
|
ctx.m_config->put("NoOfNodes", nNodes);
|
|
|
|
char tmpLine[MAX_LINE_LENGTH];
|
|
BaseString::snprintf(tmpLine, MAX_LINE_LENGTH, "EXTERNAL SYSTEM_");
|
|
strncat(tmpLine, system, MAX_LINE_LENGTH);
|
|
strncat(tmpLine, ":NoOfConnections", MAX_LINE_LENGTH);
|
|
ctx.m_config->put(tmpLine, nExtConnections);
|
|
|
|
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;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// Parse Name-Value Pair
|
|
//****************************************************************************
|
|
|
|
bool InitConfigFileParser::parseNameValuePair(Context& ctx, const char* line)
|
|
{
|
|
if (ctx.m_currentSection == NULL){
|
|
ctx.reportError("Value specified outside section");
|
|
return false;
|
|
}
|
|
|
|
// *************************************
|
|
// Split string at first occurrence of
|
|
// '=' or ':'
|
|
// *************************************
|
|
|
|
Vector<BaseString> tmp_string_split;
|
|
if (BaseString(line).split(tmp_string_split,
|
|
"=:", 2) != 2)
|
|
{
|
|
ctx.reportError("Parse error");
|
|
return false;
|
|
}
|
|
|
|
// *************************************
|
|
// 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];
|
|
|
|
// *************************************
|
|
// Remove leading and trailing chars
|
|
// *************************************
|
|
{
|
|
for (int i = 0; i < 2; i++)
|
|
tmp_string_split[i].trim("\r\n \t");
|
|
}
|
|
|
|
// *************************************
|
|
// First in split is fname
|
|
// *************************************
|
|
|
|
const char *fname= tmp_string_split[0].c_str();
|
|
|
|
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);
|
|
if (status == ConfigInfo::CI_NOTIMPLEMENTED) {
|
|
ctx.reportWarning("[%s] %s not yet implemented", ctx.fname, 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);
|
|
}
|
|
}
|
|
|
|
// ***********************
|
|
// Store name-value pair
|
|
// ***********************
|
|
|
|
return storeNameValuePair(ctx, fname, tmp_string_split[1].c_str());
|
|
}
|
|
|
|
|
|
//****************************************************************************
|
|
// STORE NAME-VALUE pair in properties section
|
|
//****************************************************************************
|
|
|
|
bool
|
|
InitConfigFileParser::storeNameValuePair(Context& ctx,
|
|
const char* fname,
|
|
const char* value) {
|
|
|
|
const char * pname = fname;
|
|
|
|
if (ctx.m_currentSection->contains(pname)) {
|
|
ctx.reportError("[%s] Parameter %s specified twice", ctx.fname, fname);
|
|
return false;
|
|
}
|
|
|
|
// ***********************
|
|
// Store name-value pair
|
|
// ***********************
|
|
|
|
const ConfigInfo::Type type = m_info->getType(ctx.m_currentInfo, fname);
|
|
switch(type){
|
|
case ConfigInfo::CI_BOOL: {
|
|
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;
|
|
}
|
|
case ConfigInfo::CI_INT:
|
|
case ConfigInfo::CI_INT64:{
|
|
Uint64 value_int;
|
|
if (!convertStringToUint64(value, value_int)) {
|
|
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"
|
|
"Legal values are between %Lu and %Lu", value, fname,
|
|
m_info->getMin(ctx.m_currentInfo, fname),
|
|
m_info->getMax(ctx.m_currentInfo, fname));
|
|
return false;
|
|
}
|
|
if(type == ConfigInfo::CI_INT){
|
|
MGM_REQUIRE(ctx.m_currentSection->put(pname, (Uint32)value_int));
|
|
} else {
|
|
MGM_REQUIRE(ctx.m_currentSection->put64(pname, value_int));
|
|
}
|
|
break;
|
|
}
|
|
case ConfigInfo::CI_STRING:
|
|
MGM_REQUIRE(ctx.m_currentSection->put(pname, value));
|
|
break;
|
|
case ConfigInfo::CI_SECTION:
|
|
abort();
|
|
}
|
|
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
|
|
//****************************************************************************
|
|
bool InitConfigFileParser::convertStringToUint64(const char* s,
|
|
Uint64& val,
|
|
Uint32 log10base) {
|
|
if (s == NULL)
|
|
return false;
|
|
if (strlen(s) == 0)
|
|
return false;
|
|
|
|
errno = 0;
|
|
char* p;
|
|
Int64 v = strtoll(s, &p, log10base);
|
|
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") ||
|
|
!strcmp(s, "True") || !strcmp(s, "TRUE") || !strcmp(s, "true") ||
|
|
!strcmp(s, "1")) {
|
|
val = true;
|
|
return true;
|
|
}
|
|
|
|
if (!strcmp(s, "N") || !strcmp(s, "n") ||
|
|
!strcmp(s, "No") || !strcmp(s, "NO") || !strcmp(s, "no") ||
|
|
!strcmp(s, "False") || !strcmp(s, "FALSE") || !strcmp(s, "false") ||
|
|
!strcmp(s, "0")) {
|
|
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);
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
// Lookup token among sections
|
|
if(!m_info->isSection(tmp)) {
|
|
free(tmp);
|
|
return NULL;
|
|
}
|
|
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];
|
|
|
|
int no = sscanf(line, "[%120[A-Z_a-z] %120[A-Z_a-z]]", token1, token2);
|
|
|
|
// Not correct no of tokens
|
|
if (no != 2) return NULL;
|
|
|
|
// Not correct keyword at end
|
|
if (!strcasecmp(token2, "DEFAULT") == 0) return NULL;
|
|
|
|
const char *token1_alias= m_info->getAlias(token1);
|
|
if (token1_alias == 0)
|
|
token1_alias= token1;
|
|
|
|
if(m_info->getInfo(token1_alias)){
|
|
return strdup(token1_alias);
|
|
}
|
|
|
|
// 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]);
|
|
}
|
|
BaseString::snprintf(ctx.pname, sizeof(ctx.pname), ctx.fname);
|
|
char buf[255];
|
|
if(ctx.type == InitConfigFileParser::Section)
|
|
BaseString::snprintf(buf, sizeof(buf), "%s", ctx.fname);
|
|
if(ctx.type == InitConfigFileParser::DefaultSection)
|
|
BaseString::snprintf(buf, sizeof(buf), "%s DEFAULT", ctx.fname);
|
|
BaseString::snprintf(ctx.fname, sizeof(ctx.fname), buf);
|
|
if(ctx.type == InitConfigFileParser::Section){
|
|
for(int i = 0; i<m_info->m_NoOfRules; i++){
|
|
const ConfigInfo::SectionRule & rule = m_info->m_SectionRules[i];
|
|
if(!strcmp(rule.m_section, "*") || !strcmp(rule.m_section, ctx.fname)){
|
|
if(!(* rule.m_sectionRule)(ctx, rule.m_ruleData)){
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(ctx.type == InitConfigFileParser::DefaultSection)
|
|
require(ctx.m_defaults->put(ctx.pname, ctx.m_currentSection));
|
|
if(ctx.type == InitConfigFileParser::Section)
|
|
require(ctx.m_config->put(ctx.pname, ctx.m_currentSection));
|
|
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)
|
|
BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
|
|
va_end(ap);
|
|
fprintf(m_errstream, "Error line %d: %s\n",
|
|
m_lineno, buf);
|
|
|
|
//m_currentSection->print();
|
|
}
|
|
|
|
void
|
|
InitConfigFileParser::Context::reportWarning(const char * fmt, ...){
|
|
va_list ap;
|
|
char buf[1000];
|
|
|
|
va_start(ap, fmt);
|
|
if (fmt != 0)
|
|
BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
|
|
va_end(ap);
|
|
fprintf(m_errstream, "Warning line %d: %s\n",
|
|
m_lineno, buf);
|
|
}
|
|
|
|
#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)
|
|
{
|
|
if(opt->comment)
|
|
((struct my_option *)opt)->app_type++;
|
|
else
|
|
((struct my_option *)opt)->app_type = order++;
|
|
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:
|
|
ctx.m_currentSection->put(options[i].name, (char*)options[i].value);
|
|
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;
|
|
}
|
|
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;
|
|
|
|
const char *save_file = defaults_file;
|
|
char *save_extra_file = defaults_extra_file;
|
|
const char *save_group_suffix = defaults_group_suffix;
|
|
|
|
if (defaults_file)
|
|
{
|
|
file.assfmt("--defaults-file=%s", defaults_file);
|
|
argv[argc++] = file.c_str();
|
|
}
|
|
|
|
if (defaults_extra_file)
|
|
{
|
|
extra_file.assfmt("--defaults-extra-file=%s", defaults_extra_file);
|
|
argv[argc++] = extra_file.c_str();
|
|
}
|
|
|
|
if (defaults_group_suffix)
|
|
{
|
|
group_suffix.assfmt("--defaults-group-suffix=%s", defaults_group_suffix);
|
|
argv[argc++] = group_suffix.c_str();
|
|
}
|
|
|
|
char ** tmp = (char**)argv;
|
|
int ret = load_defaults("my", groups, &argc, &tmp);
|
|
|
|
defaults_file = save_file;
|
|
defaults_extra_file = save_extra_file;
|
|
defaults_group_suffix = save_group_suffix;
|
|
|
|
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++)
|
|
{
|
|
if (strcmp(ConfigInfo::m_ParamInfo[i]._section, "DB") == 0 ||
|
|
strcmp(ConfigInfo::m_ParamInfo[i]._section, "API") == 0 ||
|
|
strcmp(ConfigInfo::m_ParamInfo[i]._section, "MGM") == 0)
|
|
{
|
|
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;
|
|
require(convertStringToUint64(param._min, (Uint64&)opt.min_value));
|
|
require(convertStringToUint64(param._max, (Uint64&)opt.max_value));
|
|
break;
|
|
case ConfigInfo::CI_INT64:
|
|
opt.value = (gptr*)malloc(sizeof(Int64));
|
|
opt.var_type = GET_LL;
|
|
require(convertStringToUint64(param._min, (Uint64&)opt.min_value));
|
|
require(convertStringToUint64(param._max, (Uint64&)opt.max_value));
|
|
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
|
|
*/
|
|
{
|
|
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);
|
|
ndbd = &options.back();
|
|
|
|
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);
|
|
ndb_mgmd = &options.back();
|
|
|
|
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);
|
|
mysqld = &options.back();
|
|
|
|
opt.name = "api";
|
|
opt.id = 256;
|
|
opt.value = (gptr*)malloc(sizeof(char*));
|
|
opt.var_type = GET_STR;
|
|
opt.arg_type = REQUIRED_ARG;
|
|
options.push_back(opt);
|
|
api = &options.back();
|
|
|
|
bzero(&opt, sizeof(opt));
|
|
options.push_back(opt);
|
|
}
|
|
|
|
|
|
Context ctx(m_info, m_errstream);
|
|
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;
|
|
|
|
{
|
|
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>;
|
|
|
|
#if 0
|
|
struct my_option
|
|
{
|
|
const char *name; /* Name of the option */
|
|
int id; /* unique id or short option */
|
|
const char *comment; /* option comment, for autom. --help */
|
|
gptr *value; /* The variable value */
|
|
gptr *u_max_value; /* The user def. max variable value */
|
|
const char **str_values; /* Pointer to possible values */
|
|
ulong var_type;
|
|
enum get_opt_arg_type arg_type;
|
|
longlong def_value; /* Default value */
|
|
longlong min_value; /* Min allowed value */
|
|
longlong max_value; /* Max allowed value */
|
|
longlong sub_size; /* Subtract this from given value */
|
|
long block_size; /* Value should be a mult. of this */
|
|
int app_type; /* To be used by an application */
|
|
};
|
|
#endif
|