]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
Added a lot of config error checking
authorbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>
Fri, 25 Mar 2005 02:52:43 +0000 (02:52 +0000)
committerbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>
Fri, 25 Mar 2005 02:52:43 +0000 (02:52 +0000)
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@898 e03df62e-2008-0410-955e-edbf42e46eb7

include/inspircd.h
include/inspircd_io.h
include/modules.h
src/commands.cpp
src/inspircd.cpp
src/inspircd_io.cpp
src/modules.cpp
src/modules/m_helpop.cpp

index d55ccccf47ddda402094c45059fedb898162bab1..1a19584f68986e34319d73327c8ae380d795cb18 100644 (file)
@@ -89,7 +89,7 @@ int InspIRCd(void);
 int InitConfig(void);
 void Error(int status);
 void send_error(char *s);
-void ReadConfig(void);
+void ReadConfig(bool bail,userrec* user);
 void strlower(char *n);
 
 void WriteOpers(char* text, ...);
index 28e55bd0b4f66fd85234a140cb2945069a73eb96..2ff7568c0c8bdfccb1a63dcf52ccf89cb3b01ec3 100644 (file)
@@ -23,7 +23,7 @@ bool FileExists (const char* file);
 int OpenTCPSocket (void); 
 int BindSocket (int sockfd, struct sockaddr_in client, struct sockaddr_in server, int port, char* addr);
 
-bool LoadConf(const char* filename, std::stringstream *target);
+bool LoadConf(const char* filename, std::stringstream *target, std::stringstream* errorstream);
 int ConfValue(char* tag, char* var, int index, char *result, std::stringstream *config);
 int ReadConf(std::stringstream *config_f,const char* tag, const char* var, int index, char *result);
 int ConfValueEnum(char* tag,std::stringstream *config);
index dc17b99c0b90129a2915c60c6ce4f229e02de3e3..81d76d55dd72f18d67096ed7bd9816b7e8aae446 100644 (file)
@@ -647,6 +647,7 @@ class ConfigReader : public classbase
         * (such as comments) stripped from it.
         */
        std::stringstream *cache;
+       std::stringstream *errorlog;
        /** Used to store errors
         */
        bool readerror;
@@ -703,6 +704,13 @@ class ConfigReader : public classbase
         * file does not exist or could not be opened.
         */
        bool Verify();
+       /** Dumps the list of errors in a config file to an output location. If bail is true,
+        * then the program will abort. If bail is false and user points to a valid user
+        * record, the error report will be spooled to the given user by means of NOTICE.
+        * if bool is false AND user is false, the error report will be spooled to all opers
+        * by means of a NOTICE to all opers.
+        */
+       void DumpErrors(bool bail,userrec* user);
 
        /** Returns the number of items within a tag.
         * For example if the tag was &lt;test tag="blah" data="foo"&gt; then this
index 0b9624ea810372b0956124b32b6619e82d7e0eab..85eb833c29beddd5bff1584c92de1a73b406aac7 100644 (file)
@@ -983,7 +983,7 @@ void handle_list(char **parameters, int pcnt, userrec *user)
 void handle_rehash(char **parameters, int pcnt, userrec *user)
 {
        WriteServ(user->fd,"382 %s %s :Rehashing",user->nick,CleanFilename(CONFIG_FILE));
-       ReadConfig();
+       ReadConfig(false,user);
        FOREACH_MOD OnRehash();
        WriteOpers("%s is rehashing config file %s",user->nick,CleanFilename(CONFIG_FILE));
 }
index 92808bd0b793ca43fd5a9d319d8a4a6aeca75719..634e5ac3f3c485cf0711083fed3930b12e0a92a0 100644 (file)
@@ -302,13 +302,45 @@ void readfile(file_cache &F, const char* fname)
        log(DEBUG,"readfile: loaded %s, %d lines",fname,F.size());
 }
 
-void ReadConfig(void)
+void ReadConfig(bool bail, userrec* user)
 {
        char dbg[MAXBUF],pauseval[MAXBUF],Value[MAXBUF],timeout[MAXBUF],NB[MAXBUF],flood[MAXBUF],MW[MAXBUF];
        char AH[MAXBUF],AP[MAXBUF],AF[MAXBUF];
        ConnectClass c;
+       std::stringstream errstr;
        
-       LoadConf(CONFIG_FILE,&config_f);
+       if (!LoadConf(CONFIG_FILE,&config_f,&errstr))
+       {
+               errstr.seekg(0);
+               if (bail)
+               {
+                       printf("There were errors in your configuration:\n%s",errstr.str().c_str());
+                       exit(0);
+               }
+               else
+               {
+                       char dataline[1024];
+                       if (user)
+                       {
+                               WriteServ(user->fd,"NOTICE %s :There were errors in the configuration file:",user->nick);
+                               while (!errstr.eof())
+                               {
+                                       errstr.getline(dataline,1024);
+                                       WriteServ(user->fd,"NOTICE %s :%s",user->nick,dataline);
+                               }
+                       }
+                       else
+                       {
+                               WriteOpers("There were errors in the configuration file:",user->nick);
+                               while (!errstr.eof())
+                               {
+                                       errstr.getline(dataline,1024);
+                                       WriteOpers(dataline);
+                               }
+                       }
+                       return;
+               }
+       }
          
        ConfValue("server","name",0,ServerName,&config_f);
        ConfValue("server","description",0,ServerDesc,&config_f);
@@ -3172,7 +3204,7 @@ int InspIRCd(void)
        SetupCommandTable();
        log(DEBUG,"InspIRCd: startup: default command table set up");
        
-       ReadConfig();
+       ReadConfig(true,NULL);
        if (strcmp(DieValue,"")) 
        { 
                printf("WARNING: %s\n\n",DieValue);
index a7a180a88296c9d3291ca24478f1971f7f4a14e7..2e9a350f11a24dbb696b5e1ba7e0851f2e820ad8 100644 (file)
@@ -50,8 +50,8 @@ void Killed(int status)
 
 void Rehash(int status)
 {
-  ReadConfig();
   WriteOpers("Rehashing config file %s due to SIGHUP",CONFIG_FILE);
+  ReadConfig(false,NULL);
 }
 
 
@@ -114,13 +114,148 @@ bool FileExists (const char* file)
   else { fclose (input); return(true); }
 }
 
+/* ConfProcess does the following things to a config line in the following order:
+ *
+ * Processes the line for syntax errors as shown below
+ *      (1) Line void of quotes or equals (a malformed, illegal tag format)
+ *      (2) Odd number of quotes on the line indicating a missing quote
+ *      (3) number of equals signs not equal to number of quotes / 2 (missing an equals sign)
+ *      (4) Spaces between the opening bracket (<) and the keyword
+ *      (5) Spaces between a keyword and an equals sign
+ *      (6) Spaces between an equals sign and a quote
+ * Removes trailing spaces
+ * Removes leading spaces
+ * Converts tabs to spaces
+ * Turns multiple spaces that are outside of quotes into single spaces
+ */
 
-bool LoadConf(const char* filename, std::stringstream *target)
+std::string ConfProcess(char* buffer, long linenumber, std::stringstream* errorstream, bool &error, std::string filename)
+{
+       long number_of_quotes = 0;
+       long number_of_equals = 0;
+       bool has_open_bracket = false;
+       bool in_quotes = false;
+       error = false;
+       if (!buffer)
+       {
+               return "";
+       }
+       // firstly clean up the line by stripping spaces from the start and end
+       while ((buffer[0] == ' ') && (strlen(buffer)>0)) buffer++;
+       while ((buffer[strlen(buffer)-1] == ' ') && (strlen(buffer)>0)) buffer[strlen(buffer)-1] = '\0';
+       // empty lines are syntactically valid
+       if (!strcmp(buffer,""))
+               return "";
+       else if (buffer[0] == '#')
+               return "";
+       for (int c = 0; c < strlen(buffer); c++)
+       {
+               if (buffer[c] == 9)
+                       buffer[c] = ' ';
+               // convert all spaces that are OUTSIDE quotes into hardspace (0xA0) as this will make them easier to
+               // search and replace later :)
+               if ((!in_quotes) && (buffer[c] == ' '))
+                       buffer[c] = '\xA0';
+               if ((buffer[c] == '<') && (!in_quotes))
+               {
+                       has_open_bracket = true;
+                       if (strlen(buffer) == 1)
+                       {
+                               *errorstream << "Tag without identifier at " << filename << ":" << linenumber << endl;
+                               error = true;
+                               return "";
+                       }
+                       else if ((tolower(buffer[c+1]) < 'a') || (tolower(buffer[c+1]) > 'z'))
+                       {
+                               *errorstream << "Invalid characters in identifier at " << filename << ":" << linenumber << endl;
+                               error = true;
+                               return "";
+                       }
+               }
+               if (buffer[c] == '"')
+               {
+                       number_of_quotes++;
+                       in_quotes = (!in_quotes);
+               }
+               if ((buffer[c] == '=') && (!in_quotes))
+               {
+                       number_of_equals++;
+                       if (strlen(buffer) == c)
+                       {
+                               *errorstream << "Variable without a value at " << filename << ":" << linenumber << endl;
+                               error = true;
+                               return "";
+                       }
+                       else if (buffer[c+1] != '"')
+                       {
+                               *errorstream << "Variable name not followed immediately by its value at " << filename << ":" << linenumber << endl;
+                               error = true;
+                               return "";
+                       }
+                       else if (!c)
+                       {
+                               *errorstream << "Value without a variable (line starts with '=') at " << filename << ":" << linenumber << endl;
+                               error = true;
+                               return "";
+                       }
+                       else if (buffer[c-1] == '\xA0')
+                       {
+                               *errorstream << "Variable name not followed immediately by its value at " << filename << ":" << linenumber << endl;
+                               error = true;
+                               return "";
+                       }
+               }
+       }
+       // no quotes, and no equals. something freaky.
+       if ((!number_of_quotes) || (!number_of_equals))
+       {
+               *errorstream << "Malformed tag at " << filename << ":" << linenumber << endl;
+               error = true;
+               return "";
+       }
+       // odd number of quotes. thats just wrong.
+       if ((number_of_quotes % 2) != 0)
+       {
+               *errorstream << "Missing \" at " << filename << ":" << linenumber << endl;
+               error = true;
+               return "";
+       }
+       if (number_of_equals < (number_of_quotes/2))
+       {
+               *errorstream << "Missing '=' at " << filename << ":" << linenumber << endl;
+       }
+       if (number_of_equals > (number_of_quotes/2))
+       {
+               *errorstream << "Too many '=' at " << filename << ":" << linenumber << endl;
+       }
+
+       std::string parsedata = buffer;
+       // turn multispace into single space
+       while (parsedata.find("\xA0\xA0") != std::string::npos)
+       {
+               parsedata.erase(parsedata.find("\xA0\xA0"),1);
+       }
+
+       // turn our hardspace back into softspace
+       for (int d = 0; d < parsedata.length(); d++)
+       {
+               if (parsedata[d] == '\xA0')
+                       parsedata[d] = ' ';
+       }
+
+       // and we're done, the line is fine!
+       return parsedata;
+}
+
+bool LoadConf(const char* filename, std::stringstream *target, std::stringstream* errorstream)
 {
        target->str("");
+       errorstream->str("");
+       long linenumber = 1;
        FILE* conf = fopen(filename,"r");
        if (!FileExists(filename))
        {
+               *errorstream << "File " << filename << " not found." << endl;
                return false;
        }
        char buffer[MAXBUF];
@@ -132,10 +267,17 @@ bool LoadConf(const char* filename, std::stringstream *target)
                        {
                                if ((!feof(conf)) && (buffer) && (strlen(buffer)))
                                {
-                                       if (buffer[0] != '#')
+                                       if ((buffer[0] != '#') && (buffer[0] != '\r')  && (buffer[0] != '\n'))
                                        {
-                                               *target << std::string(buffer);
+                                               bool error = false;
+                                               std::string data = ConfProcess(buffer,linenumber++,errorstream,error,filename);
+                                               if (error)
+                                               {
+                                                       return false;
+                                               }
+                                               *target << data;
                                        }
+                                       else linenumber++;
                                }
                        }
                }
index aae7a53e2b1fd020431b34e04ab57887b0a0602d..15508ae19e9bba5ed9014b2c9908e475a6c2c624 100644 (file)
@@ -566,7 +566,8 @@ int Server::CountUsers(chanrec* c)
 ConfigReader::ConfigReader()
 {
        this->cache = new std::stringstream(std::stringstream::in | std::stringstream::out);
-       this->readerror = LoadConf(CONFIG_FILE,this->cache);
+       this->errorlog = new std::stringstream(std::stringstream::in | std::stringstream::out);
+       this->readerror = LoadConf(CONFIG_FILE,this->cache,this->errorlog);
        if (!this->readerror)
                this->error = CONF_FILE_NOT_FOUND;
 }
@@ -576,13 +577,16 @@ ConfigReader::~ConfigReader()
 {
        if (this->cache)
                delete this->cache;
+       if (this->errorlog)
+               delete this->errorlog;
 }
 
 
 ConfigReader::ConfigReader(std::string filename)
 {
        this->cache = new std::stringstream(std::stringstream::in | std::stringstream::out);
-       this->readerror = LoadConf(filename.c_str(),this->cache);
+       this->errorlog = new std::stringstream(std::stringstream::in | std::stringstream::out);
+       this->readerror = LoadConf(filename.c_str(),this->cache,this->errorlog);
        if (!this->readerror)
                this->error = CONF_FILE_NOT_FOUND;
 };
@@ -656,6 +660,38 @@ long ConfigReader::GetError()
        return olderr;
 }
 
+void ConfigReader::DumpErrors(bool bail, userrec* user)
+{
+        if (bail)
+        {
+                printf("There were errors in your configuration:\n%s",errorlog->str().c_str());
+                exit(0);
+        }
+        else
+        {
+                char dataline[1024];
+                if (user)
+                {
+                        WriteServ(user->fd,"NOTICE %s :There were errors in the configuration file:",user->nick);
+                        while (!errorlog->eof())
+                        {
+                                errorlog->getline(dataline,1024);
+                                WriteServ(user->fd,"NOTICE %s :%s",user->nick,dataline);
+                        }
+                }
+                else
+                {
+                        WriteOpers("There were errors in the configuration file:",user->nick);
+                        while (!errorlog->eof())
+                        {
+                                errorlog->getline(dataline,1024);
+                                WriteOpers(dataline);
+                        }
+                }
+                return;
+        }
+}
+
 
 int ConfigReader::Enumerate(std::string tag)
 {
index 3921b7f72e312eab35380ebee9fdef47231ac7fb..4b35262400301268ae96b978865583f00d06f64e 100644 (file)
@@ -138,6 +138,11 @@ class ModuleHelpop : public Module
        {
                Srv  = new Server;
                conf = new ConfigReader;
+               if (conf->GetError())
+               {
+                       // dump errors and ABORT
+                       conf->DumpErrors(true,NULL);
+               }
 
                h_file = conf->ReadValue("helpop", "file", 0);
 
@@ -147,19 +152,14 @@ class ModuleHelpop : public Module
                }
 
                helpop = new ConfigReader(h_file);
-               if (!helpop->Verify())
-               {
-                       printf("m_helpop: Invalid Helpop File. Please Ensure it exists and is error free.");
-                       exit(0);
-               }
 
-               /*if ((helpop->ReadValue("nohelp",  "line1", 0) == "") || 
+               if ((helpop->ReadValue("nohelp",  "line1", 0) == "") || 
                     (helpop->ReadValue("nohelpo", "line1", 0) == "") ||
                     (helpop->ReadValue("start",   "line1", 0) == ""))
                {
                        printf("m_helpop: Helpop file is missing important entries. Please check the example conf.");
                        exit(0);
-               }*/
+               }
 
                if (!Srv->AddExtendedMode('h',MT_CLIENT,true,0,0))
                {