X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fconfigreader.cpp;h=2093c82c8e313366c820347560cabbf46e8eb7c3;hb=68730d4c9701b34c962302e6410908865fb2ba28;hp=a8c4dbaee4e8f13f1628955bb67d43aeedef98cc;hpb=d43120ca4a68006811b3645d0d9065ac098ddc65;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/configreader.cpp b/src/configreader.cpp index a8c4dbaee..2093c82c8 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -157,7 +157,7 @@ void ServerConfig::Update005() void ServerConfig::Send005(User* user) { for (std::vector::iterator line = ServerInstance->Config->isupport.begin(); line != ServerInstance->Config->isupport.end(); line++) - user->WriteServ("005 %s %s", user->nick, line->c_str()); + user->WriteNumeric(005, "%s %s", user->nick, line->c_str()); } bool ServerConfig::CheckOnce(const char* tag) @@ -368,14 +368,9 @@ bool ValidateDnsServer(ServerConfig* conf, const char*, const char*, ValueItem & bool ValidateServerName(ServerConfig* conf, const char*, const char*, ValueItem &data) { + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"Validating server name"); /* If we already have a servername, and they changed it, we should throw an exception. */ - if ((strcasecmp(conf->ServerName, data.GetString())) && (*conf->ServerName)) - { - throw CoreException("Configuration error: You cannot change your servername at runtime! Please restart your server for this change to be applied."); - /* We don't actually reach this return of course... */ - return false; - } - if (!strchr(data.GetString(),'.')) + if (!strchr(data.GetString(), '.')) { conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: '%s' is not a fully-qualified domain name. Changed to '%s%c'",data.GetString(),data.GetString(),'.'); std::string moo = std::string(data.GetString()).append("."); @@ -478,6 +473,8 @@ bool ValidateInvite(ServerConfig* conf, const char*, const char*, ValueItem &dat bool ValidateSID(ServerConfig* conf, const char*, const char*, ValueItem &data) { + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"Validating server id"); + const char *sid = data.GetString(); if (*sid && !conf->GetInstance()->IsSID(sid)) @@ -485,6 +482,8 @@ bool ValidateSID(ServerConfig* conf, const char*, const char*, ValueItem &data) throw CoreException(std::string(sid) + " is not a valid server ID. A server ID must be 3 characters long, with the first character a digit and the next two characters a digit or letter."); } + strlcpy(conf->sid, sid, 5); + return true; } @@ -520,13 +519,6 @@ bool InitConnect(ServerConfig* conf, const char*) { conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"Reading connect classes..."); - for (ClassVector::iterator i = conf->Classes.begin(); i != conf->Classes.end(); i++) - { - ConnectClass *c = *i; - - conf->GetInstance()->Logs->Log("CONFIG",DEBUG, "Address of class is %p", c); - } - for (ClassVector::iterator i = conf->Classes.begin(); i != conf->Classes.end() ; ) { ConnectClass* c = *i; @@ -788,9 +780,9 @@ void ServerConfig::ReportConfigError(const std::string &errormessage, bool bail, } } -void ServerConfig::Read(bool bail, User* user, int pass) +void ServerConfig::Read(bool bail, User* user) { - int rem = 0, add = 0; /* Number of modules added, number of modules removed */ + int rem = 0, add = 0; /* Number of modules added, number of modules removed */ static char debug[MAXBUF]; /* Temporary buffer for debugging value */ static char maxkeep[MAXBUF]; /* Temporary buffer for WhoWasMaxKeep value */ @@ -799,6 +791,8 @@ void ServerConfig::Read(bool bail, User* user, int pass) static char announceinvites[MAXBUF]; /* options:announceinvites setting */ errstr.clear(); + include_stack.clear(); + /* These tags MUST occur and must ONLY occur once in the config file */ static const char* Once[] = { "server", "admin", "files", "power", "options", NULL }; @@ -807,10 +801,10 @@ void ServerConfig::Read(bool bail, User* user, int pass) {"options", "softlimit", MAXCLIENTS_S, new ValueContainerUInt (&this->SoftLimit), DT_INTEGER, ValidateSoftLimit}, {"options", "somaxconn", SOMAXCONN_S, new ValueContainerInt (&this->MaxConn), DT_INTEGER, ValidateMaxConn}, {"options", "moronbanner", "Youre banned!", new ValueContainerChar (this->MoronBanner), DT_CHARPTR, NoValidation}, - {"server", "name", "", new ValueContainerChar (this->ServerName), DT_HOSTNAME, ValidateServerName}, + {"server", "name", "", new ValueContainerChar (this->ServerName), DT_HOSTNAME|DT_BOOTONLY, ValidateServerName}, {"server", "description", "Configure Me", new ValueContainerChar (this->ServerDesc), DT_CHARPTR, NoValidation}, {"server", "network", "Network", new ValueContainerChar (this->Network), DT_NOSPACES, NoValidation}, - {"server", "id", "", new ValueContainerChar (this->sid), DT_CHARPTR, ValidateSID}, + {"server", "id", "", new ValueContainerChar (this->sid), DT_CHARPTR|DT_BOOTONLY, ValidateSID}, {"admin", "name", "", new ValueContainerChar (this->AdminName), DT_CHARPTR, NoValidation}, {"admin", "email", "Mis@configu.red", new ValueContainerChar (this->AdminEmail), DT_CHARPTR, NoValidation}, {"admin", "nick", "Misconfigured", new ValueContainerChar (this->AdminNick), DT_CHARPTR, NoValidation}, @@ -948,10 +942,12 @@ void ServerConfig::Read(bool bail, User* user, int pass) /* Make a copy here so if it fails then we can carry on running with an unaffected config */ newconfig.clear(); - if (this->LoadConf(newconfig, ServerInstance->ConfigFileName, errstr, pass)) + if (this->DoInclude(newconfig, ServerInstance->ConfigFileName, errstr)) { /* If we succeeded, set the ircd config to the new one */ + ServerInstance->Threads->Mutex(true); this->config_data = newconfig; + ServerInstance->Threads->Mutex(false); } else { @@ -962,6 +958,12 @@ void ServerConfig::Read(bool bail, User* user, int pass) /* The stuff in here may throw CoreException, be sure we're in a position to catch it. */ try { + /* Check we dont have more than one of singular tags, or any of them missing + */ + for (int Index = 0; Once[Index]; Index++) + if (!CheckOnce(Once[Index])) + return; + /* Read the values of all the tags which occur once or not at all, and call their callbacks. */ for (int Index = 0; Values[Index].tag; Index++) @@ -970,8 +972,14 @@ void ServerConfig::Read(bool bail, User* user, int pass) int dt = Values[Index].datatype; bool allow_newlines = ((dt & DT_ALLOW_NEWLINE) > 0); bool allow_wild = ((dt & DT_ALLOW_WILD) > 0); + bool bootonly = ((dt & DT_BOOTONLY) > 0); dt &= ~DT_ALLOW_NEWLINE; dt &= ~DT_ALLOW_WILD; + dt &= ~DT_BOOTONLY; + + /* Silently ignore boot only values */ + if (bootonly && !bail) + continue; ConfValue(this->config_data, Values[Index].tag, Values[Index].value, Values[Index].default_value, 0, item, MAXBUF, allow_newlines); ValueItem vi(item); @@ -979,7 +987,8 @@ void ServerConfig::Read(bool bail, User* user, int pass) if (!Values[Index].validation_function(this, Values[Index].tag, Values[Index].value, vi)) throw CoreException("One or more values in your configuration file failed to validate. Please see your ircd.log for more information."); - switch (Values[Index].datatype) + ServerInstance->Threads->Mutex(true); + switch (dt) { case DT_NOSPACES: { @@ -993,6 +1002,7 @@ void ServerConfig::Read(bool bail, User* user, int pass) ValueContainerChar* vcc = (ValueContainerChar*)Values[Index].val; this->ValidateHostname(vi.GetString(), Values[Index].tag, Values[Index].value); vcc->Set(vi.GetString(), strlen(vi.GetString()) + 1); + ServerInstance->Logs->Log("CONFIG",DEFAULT,"Got %s", vi.GetString()); } break; case DT_IPADDRESS: @@ -1006,7 +1016,10 @@ void ServerConfig::Read(bool bail, User* user, int pass) { ValueContainerChar* vcc = (ValueContainerChar*)Values[Index].val; if (*(vi.GetString()) && !ServerInstance->IsChannel(vi.GetString())) + { + ServerInstance->Threads->Mutex(false); throw CoreException("The value of <"+std::string(Values[Index].tag)+":"+Values[Index].value+"> is not a valid channel name"); + } vcc->Set(vi.GetString(), strlen(vi.GetString()) + 1); } break; @@ -1037,6 +1050,7 @@ void ServerConfig::Read(bool bail, User* user, int pass) } /* We're done with this now */ delete Values[Index].val; + ServerInstance->Threads->Mutex(false); } /* Read the multiple-tag items (class tags, connect tags, etc) @@ -1045,7 +1059,9 @@ void ServerConfig::Read(bool bail, User* user, int pass) */ for (int Index = 0; MultiValues[Index].tag; Index++) { + ServerInstance->Threads->Mutex(true); MultiValues[Index].init_function(this, MultiValues[Index].tag); + ServerInstance->Threads->Mutex(false); int number_of_tags = ConfValueEnum(this->config_data, MultiValues[Index].tag); @@ -1060,81 +1076,93 @@ void ServerConfig::Read(bool bail, User* user, int pass) dt &= ~DT_ALLOW_NEWLINE; dt &= ~DT_ALLOW_WILD; - switch (dt) + ServerInstance->Threads->Mutex(true); + /* We catch and rethrow any exception here just so we can free our mutex + */ + try { - case DT_NOSPACES: - { - char item[MAXBUF]; - if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem("")); - this->ValidateNoSpaces(vl[vl.size()-1].GetString(), MultiValues[Index].tag, MultiValues[Index].items[valuenum]); - } - break; - case DT_HOSTNAME: - { - char item[MAXBUF]; - if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem("")); - this->ValidateHostname(vl[vl.size()-1].GetString(), MultiValues[Index].tag, MultiValues[Index].items[valuenum]); - } - break; - case DT_IPADDRESS: - { - char item[MAXBUF]; - if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem("")); - this->ValidateIP(vl[vl.size()-1].GetString(), MultiValues[Index].tag, MultiValues[Index].items[valuenum], allow_wild); - } - break; - case DT_CHANNEL: + switch (dt) { - char item[MAXBUF]; - if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) + case DT_NOSPACES: + { + char item[MAXBUF]; + if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) + vl.push_back(ValueItem(item)); + else + vl.push_back(ValueItem("")); + this->ValidateNoSpaces(vl[vl.size()-1].GetString(), MultiValues[Index].tag, MultiValues[Index].items[valuenum]); + } + break; + case DT_HOSTNAME: + { + char item[MAXBUF]; + if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) + vl.push_back(ValueItem(item)); + else + vl.push_back(ValueItem("")); + this->ValidateHostname(vl[vl.size()-1].GetString(), MultiValues[Index].tag, MultiValues[Index].items[valuenum]); + } + break; + case DT_IPADDRESS: + { + char item[MAXBUF]; + if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) + vl.push_back(ValueItem(item)); + else + vl.push_back(ValueItem("")); + this->ValidateIP(vl[vl.size()-1].GetString(), MultiValues[Index].tag, MultiValues[Index].items[valuenum], allow_wild); + } + break; + case DT_CHANNEL: + { + char item[MAXBUF]; + if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) + vl.push_back(ValueItem(item)); + else + vl.push_back(ValueItem("")); + if (!ServerInstance->IsChannel(vl[vl.size()-1].GetString())) + throw CoreException("The value of <"+std::string(MultiValues[Index].tag)+":"+MultiValues[Index].items[valuenum]+"> number "+ConvToStr(tagnum + 1)+" is not a valid channel name"); + } + break; + case DT_CHARPTR: + { + char item[MAXBUF]; + if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) + vl.push_back(ValueItem(item)); + else + vl.push_back(ValueItem("")); + } + break; + case DT_INTEGER: + { + int item = 0; + if (ConfValueInteger(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item)) + vl.push_back(ValueItem(item)); + else + vl.push_back(ValueItem(0)); + } + break; + case DT_BOOLEAN: + { + bool item = ConfValueBool(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum); vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem("")); - if (!ServerInstance->IsChannel(vl[vl.size()-1].GetString())) - throw CoreException("The value of <"+std::string(MultiValues[Index].tag)+":"+MultiValues[Index].items[valuenum]+"> number "+ConvToStr(tagnum + 1)+" is not a valid channel name"); + } + break; + default: + /* Someone was smoking craq if we got here, and we're all gonna die. */ + break; } - break; - case DT_CHARPTR: - { - char item[MAXBUF]; - if (ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item, MAXBUF, allow_newlines)) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem("")); - } - break; - case DT_INTEGER: - { - int item = 0; - if (ConfValueInteger(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum, item)) - vl.push_back(ValueItem(item)); - else - vl.push_back(ValueItem(0)); - } - break; - case DT_BOOLEAN: - { - bool item = ConfValueBool(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], MultiValues[Index].items_default[valuenum], tagnum); - vl.push_back(ValueItem(item)); - } - break; - default: - /* Someone was smoking craq if we got here, and we're all gonna die. */ - break; } + catch (CoreException &e) + { + ServerInstance->Threads->Mutex(false); + throw e; + } + ServerInstance->Threads->Mutex(false); } - MultiValues[Index].validation_function(this, MultiValues[Index].tag, (char**)MultiValues[Index].items, vl, MultiValues[Index].datatype); + MultiValues[Index].validation_function(this, MultiValues[Index].tag, (char**)MultiValues[Index].items, vl, MultiValues[Index].datatype); } - MultiValues[Index].finish_function(this, MultiValues[Index].tag); + MultiValues[Index].finish_function(this, MultiValues[Index].tag); } } @@ -1145,51 +1173,14 @@ void ServerConfig::Read(bool bail, User* user, int pass) return; } - /** XXX END PASS **/ - ServerInstance->Logs->Log("CONFIG",DEBUG,"End config pass %d", pass); - - if (pass == 0) - { - /* FIRST PASS: Set up commands, load modules. - * We cannot gaurantee that all config is correct - * at this point - */ - - if (pass == 0) - { - ServerInstance->Logs->Log("CONFIG",DEBUG, "Downloading configuration"); - - TotalDownloaded = 0; - FileErrors = 0; - } - - if (!ServerInstance->Res) - ServerInstance->Res = new DNS(ServerInstance); - /** Note: This is safe, the method checks for user == NULL */ - ServerInstance->Parser->SetupCommandTable(user); - ServerInstance->Modules->LoadAll(); - } - else - { - /* SECOND PASS: Call modules to read configs, finalize - * stuff. Check that we have at least the required number - * of whichever items. This is no longer done first. - */ - /* Close all logs at this point and reopen logs. */ - ServerInstance->Logs->CloseLogs(); - ServerInstance->Logs->OpenFileLogs(); - ConfigReader* n = new ConfigReader(ServerInstance); - FOREACH_MOD(I_OnReadConfig,OnReadConfig(this, n)); - - for (int Index = 0; Once[Index]; Index++) - if (!CheckOnce(Once[Index])) - return; - } - // write once here, to try it out and make sure its ok ServerInstance->WritePID(this->PID); - ServerInstance->Logs->Log("CONFIG",DEFAULT,"Done reading configuration file."); + ServerInstance->Log(DEFAULT,"Done reading configuration file."); + + /* Switch over logfiles */ + ServerInstance->Logs->CloseLogs(); + ServerInstance->Logs->OpenFileLogs(); /* If we're rehashing, let's load any new modules, and unload old ones */ @@ -1201,6 +1192,7 @@ void ServerConfig::Read(bool bail, User* user, int pass) if (pl.size() && user) { + ServerInstance->Threads->Mutex(true); user->WriteServ("NOTICE %s :*** Not all your client ports could be bound.", user->nick); user->WriteServ("NOTICE %s :*** The following port(s) failed to bind:", user->nick); int j = 1; @@ -1208,134 +1200,74 @@ void ServerConfig::Read(bool bail, User* user, int pass) { user->WriteServ("NOTICE %s :*** %d. IP: %s Port: %lu", user->nick, j, i->first.empty() ? "" : i->first.c_str(), (unsigned long)i->second); } + ServerInstance->Threads->Mutex(false); } - } - if (!removed_modules.empty()) - { - for (std::vector::iterator removing = removed_modules.begin(); removing != removed_modules.end(); removing++) + ServerInstance->Threads->Mutex(true); + if (!removed_modules.empty()) { - if (ServerInstance->Modules->Unload(removing->c_str())) + for (std::vector::iterator removing = removed_modules.begin(); removing != removed_modules.end(); removing++) { - ServerInstance->SNO->WriteToSnoMask('A', "REHASH UNLOADED MODULE: %s",removing->c_str()); - if (user) - user->WriteServ("973 %s %s :Module %s successfully unloaded.",user->nick, removing->c_str(), removing->c_str()); - rem++; - } - else - { - if (user) - user->WriteServ("972 %s %s :%s",user->nick, removing->c_str(), ServerInstance->Modules->LastError().c_str()); + if (ServerInstance->Modules->Unload(removing->c_str())) + { + ServerInstance->SNO->WriteToSnoMask('A', "*** REHASH UNLOADED MODULE: %s",removing->c_str()); + + if (user) + user->WriteNumeric(973, "%s %s :Module %s successfully unloaded.",user->nick, removing->c_str(), removing->c_str()); + + rem++; + } + else + { + if (user) + user->WriteNumeric(972, "%s %s :Failed to unload module %s: %s",user->nick, removing->c_str(), removing->c_str(), ServerInstance->Modules->LastError().c_str()); + } } } - } - if (!added_modules.empty()) - { - for (std::vector::iterator adding = added_modules.begin(); adding != added_modules.end(); adding++) + if (!added_modules.empty()) { - /* Skip over modules that are aleready loaded for some reason */ - if (ServerInstance->Modules->Find(*adding)) - continue; - - if (bail) - printf_c("[\033[1;32m*\033[0m] Loading module:\t\033[1;32m%s\033[0m\n", adding->c_str()); - - if (ServerInstance->Modules->Load(adding->c_str())) + for (std::vector::iterator adding = added_modules.begin(); adding != added_modules.end(); adding++) { - ServerInstance->SNO->WriteToSnoMask('A', "REHASH LOADED MODULE: %s",adding->c_str()); - if (user) - user->WriteServ("975 %s %s :Module %s successfully loaded.",user->nick, adding->c_str(), adding->c_str()); + if (ServerInstance->Modules->Load(adding->c_str())) + { + ServerInstance->SNO->WriteToSnoMask('A', "*** REHASH LOADED MODULE: %s",adding->c_str()); - add++; - } - else - { - if (user) - user->WriteServ("974 %s %s :%s",user->nick, adding->c_str(), ServerInstance->Modules->LastError().c_str()); + if (user) + user->WriteNumeric(975, "%s %s :Module %s successfully loaded.",user->nick, adding->c_str(), adding->c_str()); - if (bail) + add++; + } + else { - printf_c("\n[\033[1;31m*\033[0m] %s\n\n", ServerInstance->Modules->LastError().c_str()); - ServerInstance->Exit(EXIT_STATUS_MODULE); + if (user) + user->WriteNumeric(974, "%s %s :Failed to load module %s: %s",user->nick, adding->c_str(), adding->c_str(), ServerInstance->Modules->LastError().c_str()); } } } + + ServerInstance->Log(DEFAULT,"Successfully unloaded %lu of %lu modules and loaded %lu of %lu modules.",(unsigned long)rem,(unsigned long)removed_modules.size(),(unsigned long)add,(unsigned long)added_modules.size()); + + ServerInstance->Threads->Mutex(false); + } - ServerInstance->Logs->Log("CONFIG",DEFAULT,"Successfully unloaded %lu of %lu modules and loaded %lu of %lu modules.",(unsigned long)rem,(unsigned long)removed_modules.size(),(unsigned long)add,(unsigned long)added_modules.size()); + /** Note: This is safe, the method checks for user == NULL */ + ServerInstance->Threads->Mutex(true); + ServerInstance->Parser->SetupCommandTable(user); + ServerInstance->Threads->Mutex(false); if (user) user->WriteServ("NOTICE %s :*** Successfully rehashed server.", user->nick); else - ServerInstance->SNO->WriteToSnoMask('A', "Successfully rehashed server."); -} - -/* XXX: This can and will block! */ -void ServerConfig::DoDownloads() -{ - ServerInstance->Logs->Log("CONFIG",DEBUG,"In DoDownloads()"); - - /* Reads all local files into the IncludedFiles map, then initiates sockets for the remote ones */ - for (std::map::iterator x = IncludedFiles.begin(); x != IncludedFiles.end(); ++x) - { - if (CompletedFiles.find(x->first) != CompletedFiles.end()) - continue; - - ServerInstance->Logs->Log("CONFIG",DEBUG,"StartDownloads File: %s", x->first.c_str()); - - std::string file = x->first; - if ((file[0] == '/') || (file.substr(0, 7) == "file://")) - { - /* For file:// schema files, we use std::ifstream which is a derivative of std::istream. - * For all other file schemas, we use a std::stringstream. - */ - - /* Add our own ifstream */ - std::ifstream* conf = new std::ifstream(file.c_str()); - if (!conf->fail()) - { - ServerInstance->Logs->Log("CONFIG",DEBUG,"file:// schema file %s loaded OK", file.c_str()); - delete x->second; - x->second = conf; - } - else - { - delete x->second; - x->second = NULL; - FileErrors++; - } - TotalDownloaded++; - } - else - { - /* Modules handle these */ - ServerInstance->Logs->Log("CONFIG",DEBUG,"Module-handled schema for %s", x->first.c_str()); + ServerInstance->SNO->WriteToSnoMask('A', "*** Successfully rehashed server."); - /* For now, error it */ - int MOD_RESULT = 0; - FOREACH_RESULT(I_OnDownloadFile, OnDownloadFile(file, x->second)); - if (MOD_RESULT == 0) - { - /* No module claimed this file */ - TotalDownloaded++; - FileErrors++; - delete x->second; - x->second = NULL; - } - else - { - /* Search new file here for more includes to parse */ - } - } - CompletedFiles[x->first] = true; - } } -bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::ostringstream &errorstream, int pass, std::istream *scan_for_includes_only) + +bool ServerConfig::LoadConf(ConfigDataHash &target, FILE* &conf, const char* filename, std::ostringstream &errorstream) { std::string line; - std::istream* conf = NULL; char ch; long linenumber; bool in_tag; @@ -1348,65 +1280,31 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::o in_quote = false; in_comment = false; - if (scan_for_includes_only) - { - ServerInstance->Logs->Log("CONFIG",DEBUG,"scan_for_includes_only set"); - conf = scan_for_includes_only; - } + ServerInstance->Logs->Log("CONFIG", DEBUG, "Reading %s", filename); - if (std::string(filename) == CONFIG_FILE) + /* Check if the file open failed first */ + if (!conf) { - if (!scan_for_includes_only) - { - conf = new std::ifstream(filename); - if (conf->fail()) - { - errorstream << "File " << filename << " could not be opened." << std::endl; - return false; - } - } + errorstream << "LoadConf: Couldn't open config file: " << filename << std::endl; + return false; } - else + + for (unsigned int t = 0; t < include_stack.size(); t++) { - std::map::iterator x = IncludedFiles.find(filename); - if (x == IncludedFiles.end()) - { - if (pass == 0) - { - ServerInstance->Logs->Log("CONFIG",DEBUG,"Push include file %s onto map", filename); - /* First pass, we insert the file into a map, and just return true */ - IncludedFiles.insert(std::make_pair(filename,new std::stringstream)); - return true; - } - else - { - /* Second pass, look for the file in the map */ - ServerInstance->Logs->Log("CONFIG",DEBUG,"We are in the second pass, and %s is not in the map!", filename); - errorstream << "File " << filename << " could not be opened." << std::endl; - return false; - } - } - else + if (std::string(filename) == include_stack[t]) { - if (!scan_for_includes_only) - { - if (x->second) - conf = IncludedFiles.find(filename)->second; - else - { - errorstream << "File " << filename << " could not be opened." << std::endl; - return false; - } - } + errorstream << "File " << filename << " is included recursively (looped inclusion)." << std::endl; + return false; } } - ServerInstance->Logs->Log("CONFIG",DEBUG,"Start to read conf %s %08lx", filename, conf); + /* It's not already included, add it to the list of files we've loaded */ + include_stack.push_back(filename); /* Start reading characters... */ - while (conf->get(ch)) + while (!feof(conf)) { - + ch = fgetc(conf); /* * Fix for moronic windows issue spotted by Adremelech. * Some windows editors save text files as utf-16, which is @@ -1418,8 +1316,6 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::o if ((character_count++ < 2) && (ch == '\xFF' || ch == '\xFE')) { errorstream << "File " << filename << " cannot be read, as it is encoded in braindead UTF-16. Save your file as plain ASCII!" << std::endl; - if (!scan_for_includes_only) - delete conf; return false; } @@ -1465,8 +1361,9 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::o { line += ch; char real_character; - if (conf->get(real_character)) + if (!feof(conf)) { + real_character = fgetc(conf); if (real_character == 'n') real_character = '\n'; line += real_character; @@ -1475,8 +1372,6 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::o else { errorstream << "End of file after a \\, what did you want to escape?: " << filename << ":" << linenumber << std::endl; - if (!scan_for_includes_only) - delete conf; return false; } } @@ -1491,8 +1386,6 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::o if (!in_quote) { errorstream << "Got another opening < when the first one wasn't closed: " << filename << ":" << linenumber << std::endl; - if (!scan_for_includes_only) - delete conf; return false; } } @@ -1501,8 +1394,6 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::o if (in_quote) { errorstream << "We're in a quote but outside a tag, interesting. " << filename << ":" << linenumber << std::endl; - if (!scan_for_includes_only) - delete conf; return false; } else @@ -1541,7 +1432,6 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::o } else if (ch == '>') { - if (!in_quote) { if (in_tag) { @@ -1553,20 +1443,14 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::o * LoadConf() and load the included config into the same ConfigDataHash */ - if (!this->ParseLine(target, line, linenumber, errorstream, pass, scan_for_includes_only)) - { - if (!scan_for_includes_only) - delete conf; + if (!this->ParseLine(target, line, linenumber, errorstream)) return false; - } line.clear(); } else { errorstream << "Got a closing > when we weren't inside a tag: " << filename << ":" << linenumber << std::endl; - if (!scan_for_includes_only) - delete conf; return false; } } @@ -1580,17 +1464,16 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::o is a newline missing from the end of the file: " << filename << ":" << linenumber << std::endl; } - if (!scan_for_includes_only) - delete conf; return true; } -bool ServerConfig::LoadConf(ConfigDataHash &target, const std::string &filename, std::ostringstream &errorstream, int pass, std::istream* scan_for_includs_only) + +bool ServerConfig::LoadConf(ConfigDataHash &target, FILE* &conf, const std::string &filename, std::ostringstream &errorstream) { - return this->LoadConf(target, filename.c_str(), errorstream, pass, scan_for_includs_only); + return this->LoadConf(target, conf, filename.c_str(), errorstream); } -bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long &linenumber, std::ostringstream &errorstream, int pass, std::istream* scan_for_includes_only) +bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long &linenumber, std::ostringstream &errorstream) { std::string tagname; std::string current_key; @@ -1679,9 +1562,8 @@ bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long &li } else { - /* Leaving quotes, we have the value */ - if (!scan_for_includes_only) - results.push_back(KeyVal(current_key, current_value)); + /* Leaving the quotes, we have the current value */ + results.push_back(KeyVal(current_key, current_value)); // std::cout << "<" << tagname << ":" << current_key << "> " << current_value << std::endl; @@ -1690,7 +1572,13 @@ bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long &li if ((tagname == "include") && (current_key == "file")) { - if (!this->DoInclude(target, current_value, errorstream, pass, scan_for_includes_only)) + if (!this->DoInclude(target, current_value, errorstream)) + return false; + } + else if ((tagname == "include") && (current_key == "executable")) + { + /* Pipe an executable and use its stdout as config data */ + if (!this->DoPipe(target, current_value, errorstream)) return false; } @@ -1710,13 +1598,28 @@ bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long &li } /* Finished parsing the tag, add it to the config hash */ - if (!scan_for_includes_only) - target.insert(std::pair (tagname, results)); + target.insert(std::pair (tagname, results)); return true; } -bool ServerConfig::DoInclude(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream, int pass, std::istream* scan_for_includes_only) +bool ServerConfig::DoPipe(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream) +{ + FILE* conf = popen(file.c_str(), "r"); + bool ret = false; + + if (conf) + { + ret = LoadConf(target, conf, file.c_str(), errorstream); + pclose(conf); + } + else + errorstream << "Couldn't execute: " << file << std::endl; + + return ret; +} + +bool ServerConfig::DoInclude(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream) { std::string confpath; std::string newfile; @@ -1742,7 +1645,18 @@ bool ServerConfig::DoInclude(ConfigDataHash &target, const std::string &file, st } } - return LoadConf(target, newfile, errorstream, pass, scan_for_includes_only); + FILE* conf = fopen(newfile.c_str(), "r"); + bool ret = false; + + if (conf) + { + ret = LoadConf(target, conf, newfile, errorstream); + fclose(conf); + } + else + errorstream << "Couldn't open config file: " << file << std::endl; + + return ret; } bool ServerConfig::ConfValue(ConfigDataHash &target, const char* tag, const char* var, int index, char* result, int length, bool allow_linefeeds) @@ -2308,7 +2222,10 @@ bool DoneELine(ServerConfig* conf, const char* tag) void ConfigReaderThread::Run() { - ServerInstance->Config->Read(true, NULL, 0); - ServerInstance->Config->Read(true, NULL, 1); + /* TODO: TheUser may be invalid by the time we get here! Check its validity, or pass a UID would be better */ + ServerInstance->Config->Read(do_bail, TheUser); + ServerInstance->Threads->Mutex(true); + this->SetExitFlag(); + ServerInstance->Threads->Mutex(false); }