X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fconfigreader.cpp;h=a3471327918b5ca11ba0f8ff60deeee291b2b6fd;hb=5f8f96e0b6ed20f01dcda78e19e6fb1168d27f5f;hp=e0dd021ba163611046547e485bf525d3d151c25d;hpb=f995b32ff4a570f3c35521e5d426286dd25c1c89;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/configreader.cpp b/src/configreader.cpp index e0dd021ba..a34713279 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -284,7 +284,7 @@ bool ValidateMaxTargets(ServerConfig* conf, const char*, const char*, ValueItem { if ((data.GetInteger() < 0) || (data.GetInteger() > 31)) { - conf->GetInstance()->Log(DEFAULT,"WARNING: value is greater than 31 or less than 0, set to 20."); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: value is greater than 31 or less than 0, set to 20."); data.Set(20); } return true; @@ -294,7 +294,7 @@ bool ValidateSoftLimit(ServerConfig* conf, const char*, const char*, ValueItem & { if ((data.GetInteger() < 1) || (data.GetInteger() > MAXCLIENTS)) { - conf->GetInstance()->Log(DEFAULT,"WARNING: value is greater than %d or less than 0, set to %d.",MAXCLIENTS,MAXCLIENTS); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: value is greater than %d or less than 0, set to %d.",MAXCLIENTS,MAXCLIENTS); data.Set(MAXCLIENTS); } return true; @@ -303,7 +303,7 @@ bool ValidateSoftLimit(ServerConfig* conf, const char*, const char*, ValueItem & bool ValidateMaxConn(ServerConfig* conf, const char*, const char*, ValueItem &data) { if (data.GetInteger() > SOMAXCONN) - conf->GetInstance()->Log(DEFAULT,"WARNING: value may be higher than the system-defined SOMAXCONN value!"); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: value may be higher than the system-defined SOMAXCONN value!"); return true; } @@ -334,7 +334,7 @@ bool ValidateDnsServer(ServerConfig* conf, const char*, const char*, ValueItem & { std::string nameserver; // attempt to look up their nameserver from /etc/resolv.conf - conf->GetInstance()->Log(DEFAULT,"WARNING: not defined, attempting to find working server in /etc/resolv.conf..."); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: not defined, attempting to find working server in /etc/resolv.conf..."); std::ifstream resolv("/etc/resolv.conf"); bool found_server = false; @@ -347,19 +347,19 @@ bool ValidateDnsServer(ServerConfig* conf, const char*, const char*, ValueItem & resolv >> nameserver; data.Set(nameserver.c_str()); found_server = true; - conf->GetInstance()->Log(DEFAULT," set to '%s' as first resolver in /etc/resolv.conf.",nameserver.c_str()); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT," set to '%s' as first resolver in /etc/resolv.conf.",nameserver.c_str()); } } if (!found_server) { - conf->GetInstance()->Log(DEFAULT,"/etc/resolv.conf contains no viable nameserver entries! Defaulting to nameserver '127.0.0.1'!"); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"/etc/resolv.conf contains no viable nameserver entries! Defaulting to nameserver '127.0.0.1'!"); data.Set("127.0.0.1"); } } else { - conf->GetInstance()->Log(DEFAULT,"/etc/resolv.conf can't be opened! Defaulting to nameserver '127.0.0.1'!"); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"/etc/resolv.conf can't be opened! Defaulting to nameserver '127.0.0.1'!"); data.Set("127.0.0.1"); } } @@ -377,7 +377,7 @@ bool ValidateServerName(ServerConfig* conf, const char*, const char*, ValueItem } if (!strchr(data.GetString(),'.')) { - conf->GetInstance()->Log(DEFAULT,"WARNING: '%s' is not a fully-qualified domain name. Changed to '%s%c'",data.GetString(),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("."); data.Set(moo.c_str()); } @@ -388,7 +388,7 @@ bool ValidateNetBufferSize(ServerConfig* conf, const char*, const char*, ValueIt { if ((!data.GetInteger()) || (data.GetInteger() > 65535) || (data.GetInteger() < 1024)) { - conf->GetInstance()->Log(DEFAULT,"No NetBufferSize specified or size out of range, setting to default of 10240."); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"No NetBufferSize specified or size out of range, setting to default of 10240."); data.Set(10240); } return true; @@ -398,7 +398,7 @@ bool ValidateMaxWho(ServerConfig* conf, const char*, const char*, ValueItem &dat { if ((data.GetInteger() > 65535) || (data.GetInteger() < 1)) { - conf->GetInstance()->Log(DEFAULT," size out of range, setting to default of 128."); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT," size out of range, setting to default of 128."); data.Set(128); } return true; @@ -501,7 +501,7 @@ bool ValidateWhoWas(ServerConfig* conf, const char*, const char*, ValueItem &dat if (conf->WhoWasMaxKeep < 3600) { conf->WhoWasMaxKeep = 3600; - conf->GetInstance()->Log(DEFAULT,"WARNING: value less than 3600, setting to default 3600"); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: value less than 3600, setting to default 3600"); } Command* whowas_command = conf->GetInstance()->Parser->GetHandler("WHOWAS"); @@ -518,13 +518,13 @@ bool ValidateWhoWas(ServerConfig* conf, const char*, const char*, ValueItem &dat */ bool InitConnect(ServerConfig* conf, const char*) { - conf->GetInstance()->Log(DEFAULT,"Reading connect classes..."); + 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()->Log(DEBUG, "Address of class is %p", c); + conf->GetInstance()->Logs->Log("CONFIG",DEBUG, "Address of class is %p", c); } for (ClassVector::iterator i = conf->Classes.begin(); i != conf->Classes.end() ; ) @@ -534,7 +534,7 @@ bool InitConnect(ServerConfig* conf, const char*) /* only delete a class with refcount 0 */ if (c->RefCount == 0) { - conf->GetInstance()->Log(DEFAULT, "Removing connect class, refcount is 0!"); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT, "Removing connect class, refcount is 0!"); /* This was causing a crash, because we'd set i to .begin() just here, but then the for loop's increment would * set it to .begin() + 1. Which if it was already the last thing in the list, wasn't good. @@ -588,12 +588,12 @@ bool DoConnect(ServerConfig* conf, const char*, char**, ValueList &values, int*) { /* reenable class so users can be shoved into it :P */ cc->SetDisabled(false); - conf->GetInstance()->Log(DEFAULT, "Not adding class, it already exists!"); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT, "Not adding class, it already exists!"); return true; } } - conf->GetInstance()->Log(DEFAULT,"Adding a connect class!"); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"Adding a connect class!"); if (*parent) { @@ -604,7 +604,7 @@ bool DoConnect(ServerConfig* conf, const char*, char**, ValueList &values, int*) for (; item != conf->Classes.end(); ++item) { ConnectClass* cc = *item; - conf->GetInstance()->Log(DEBUG,"Class: %s", cc->GetName().c_str()); + conf->GetInstance()->Logs->Log("CONFIG",DEBUG,"Class: %s", cc->GetName().c_str()); if (cc->GetName() == parent) { ConnectClass* newclass = new ConnectClass(name, cc); @@ -640,7 +640,7 @@ bool DoConnect(ServerConfig* conf, const char*, char**, ValueList &values, int*) */ bool DoneConnect(ServerConfig *conf, const char*) { - conf->GetInstance()->Log(DEFAULT, "Done adding connect classes!"); + conf->GetInstance()->Logs->Log("CONFIG",DEFAULT, "Done adding connect classes!"); return true; } @@ -751,7 +751,7 @@ bool DoneMaxBans(ServerConfig*, const char*) void ServerConfig::ReportConfigError(const std::string &errormessage, bool bail, User* user) { - ServerInstance->Log(DEFAULT, "There were errors in your configuration file: %s", errormessage.c_str()); + ServerInstance->Logs->Log("CONFIG",DEFAULT, "There were errors in your configuration file: %s", errormessage.c_str()); if (bail) { /* Unneeded because of the ServerInstance->Log() aboive? */ @@ -788,9 +788,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 +799,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 }; @@ -948,10 +950,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->LoadConf(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 +966,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++) @@ -979,6 +989,7 @@ 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."); + ServerInstance->Threads->Mutex(true); switch (Values[Index].datatype) { case DT_NOSPACES: @@ -1006,7 +1017,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 +1051,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 +1060,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 +1077,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: - { - 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: + 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("")); + } + break; + default: + /* Someone was smoking craq if we got here, and we're all gonna die. */ + break; } - 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,52 +1174,15 @@ void ServerConfig::Read(bool bail, User* user, int pass) return; } - /** XXX END PASS **/ - ServerInstance->Log(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->Log(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->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 */ if (!bail) @@ -1201,6 +1193,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 +1201,75 @@ 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->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 :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->WriteServ("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->WriteServ("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->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()); + /** 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->Log(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->Log(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. - */ + ServerInstance->SNO->WriteToSnoMask('A', "*** Successfully rehashed server."); - /* Add our own ifstream */ - std::ifstream* conf = new std::ifstream(file.c_str()); - if (!conf->fail()) - { - ServerInstance->Log(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->Log(DEBUG,"Module-handled schema for %s", x->first.c_str()); - - /* 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, const char* filename, std::ostringstream &errorstream) { + std::ifstream conf(filename); std::string line; - std::istream* conf = NULL; char ch; long linenumber; bool in_tag; @@ -1348,63 +1282,30 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::o in_quote = false; in_comment = false; - if (scan_for_includes_only) + /* Check if the file open failed first */ + if (!conf) { - ServerInstance->Log(DEBUG,"scan_for_includes_only set"); - conf = scan_for_includes_only; + errorstream << "LoadConf: Couldn't open config file: " << filename << std::endl; + return false; } - if (std::string(filename) == CONFIG_FILE) - { - if (!scan_for_includes_only) - { - conf = new std::ifstream(filename); - if (conf->fail()) - { - errorstream << "File " << filename << " could not be opened." << std::endl; - return false; - } - } - } - else + /* Fix the chmod of the file to restrict it to the current user and group */ + chmod(filename,0600); + + for (unsigned int t = 0; t < include_stack.size(); t++) { - std::map::iterator x = IncludedFiles.find(filename); - if (x == IncludedFiles.end()) + if (std::string(filename) == include_stack[t]) { - if (pass == 0) - { - ServerInstance->Log(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->Log(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 (!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->Log(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 (conf.get(ch)) { /* @@ -1418,8 +1319,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,7 +1364,7 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::o { line += ch; char real_character; - if (conf->get(real_character)) + if (conf.get(real_character)) { if (real_character == 'n') real_character = '\n'; @@ -1475,8 +1374,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 +1388,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 +1396,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 +1434,6 @@ bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::o } else if (ch == '>') { - if (!in_quote) { if (in_tag) { @@ -1553,20 +1445,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 +1466,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, const std::string &filename, std::ostringstream &errorstream) { - return this->LoadConf(target, filename.c_str(), errorstream, pass, scan_for_includs_only); + return this->LoadConf(target, 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 +1564,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 +1574,7 @@ 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; } @@ -1710,13 +1594,12 @@ 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::DoInclude(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream) { std::string confpath; std::string newfile; @@ -1742,7 +1625,7 @@ bool ServerConfig::DoInclude(ConfigDataHash &target, const std::string &file, st } } - return LoadConf(target, newfile, errorstream, pass, scan_for_includes_only); + return LoadConf(target, newfile, errorstream); } bool ServerConfig::ConfValue(ConfigDataHash &target, const char* tag, const char* var, int index, char* result, int length, bool allow_linefeeds) @@ -1779,7 +1662,7 @@ bool ServerConfig::ConfValue(ConfigDataHash &target, const std::string &tag, con { if ((!allow_linefeeds) && (j->second.find('\n') != std::string::npos)) { - ServerInstance->Log(DEFAULT, "Value of <" + tag + ":" + var+ "> contains a linefeed, and linefeeds in this value are not permitted -- stripped to spaces."); + ServerInstance->Logs->Log("CONFIG",DEFAULT, "Value of <" + tag + ":" + var+ "> contains a linefeed, and linefeeds in this value are not permitted -- stripped to spaces."); for (std::string::iterator n = j->second.begin(); n != j->second.end(); n++) if (*n == '\n') *n = ' '; @@ -2305,3 +2188,10 @@ bool DoneELine(ServerConfig* conf, const char* tag) conf->GetInstance()->XLines->CheckELines(); return true; } + +void ConfigReaderThread::Run() +{ + /* 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); +} +