Implement new configuration option "IncludeDir"
authorAlexander Barton <alex@barton.de>
Fri, 24 May 2013 20:29:41 +0000 (22:29 +0200)
committerAlexander Barton <alex@barton.de>
Fri, 24 May 2013 20:34:53 +0000 (22:34 +0200)
The option "IncludeDir" in the [Options] section can be used
to specify a directory which can contain further configuration
files and configuration file snippets matching the pattern
"*.conf" that should be read in after the main configuration
file ("ngircd.conf" by default) has been parsed.

Closes bug #157.

doc/sample-ngircd.conf.tmpl
man/ngircd.conf.5.tmpl
src/ngircd/conf.c

index 822fd5d..31333ec 100644 (file)
        # prepended to their user name.
        ;Ident = yes
 
+       # Directory containing configuration snippets (*.conf), that should
+       # be read in after parsing this configuration file.
+       ;IncludeDir = :ETCDIR:/conf.d
+
        # Enhance user privacy slightly (useful for IRC server on TOR or I2P)
        # by censoring some information like idle time, logon time, etc.
        ;MorePrivacy = no
index e5485db..64acd92 100644 (file)
@@ -1,7 +1,7 @@
 .\"
 .\" ngircd.conf(5) manual page template
 .\"
-.TH ngircd.conf 5 "Feb 2013" ngIRCd "ngIRCd Manual"
+.TH ngircd.conf 5 "May 2013" ngIRCd "ngIRCd Manual"
 .SH NAME
 ngircd.conf \- configuration file of ngIRCd
 .SH SYNOPSIS
@@ -265,6 +265,11 @@ Users identified using IDENT are registered without the "~" character
 prepended to their user name.
 Default: yes.
 .TP
+.TP
+\fBIncludeDir\fR (string)
+Directory containing configuration snippets (*.conf), that should be read in
+after parsing the current configuration file.
+Default: none.
 \fBMorePrivacy\fR (boolean)
 This will cause ngIRCd to censor user idle time, logon time as well as the
 part/quit messages (that are sometimes used to inform everyone about which
index eee1925..d7e1a15 100644 (file)
@@ -34,7 +34,7 @@
 #include <grp.h>
 #include <sys/types.h>
 #include <unistd.h>
-
+#include <dirent.h>
 
 #include "array.h"
 #include "ngircd.h"
@@ -55,6 +55,7 @@ static int New_Server_Idx;
 
 static char Conf_MotdFile[FNAME_LEN];
 static char Conf_HelpFile[FNAME_LEN];
+static char Conf_IncludeDir[FNAME_LEN];
 
 static void Set_Defaults PARAMS(( bool InitServers ));
 static bool Read_Config PARAMS(( bool TestOnly, bool IsStarting ));
@@ -404,6 +405,7 @@ Conf_Test( void )
 #ifdef IDENT
        printf("  Ident = %s\n", yesno_to_str(Conf_Ident));
 #endif
+       printf("  IncludeDir = %s\n", Conf_IncludeDir);
        printf("  MorePrivacy = %s\n", yesno_to_str(Conf_MorePrivacy));
        printf("  NoticeAuth = %s\n", yesno_to_str(Conf_NoticeAuth));
        printf("  OperCanUseMode = %s\n", yesno_to_str(Conf_OperCanMode));
@@ -778,6 +780,7 @@ Set_Defaults(bool InitServers)
 #else
        Conf_Ident = false;
 #endif
+       strcpy(Conf_IncludeDir, "");
        Conf_MorePrivacy = false;
        Conf_NoticeAuth = false;
        Conf_OperCanMode = false;
@@ -876,8 +879,11 @@ static bool
 Read_Config(bool TestOnly, bool IsStarting)
 {
        const UINT16 defaultport = 6667;
+       char *ptr, file[FNAME_LEN];
+       struct dirent *entry;
        int i, n;
        FILE *fd;
+       DIR *dh;
 
        /* Open configuration file */
        fd = fopen( NGIRCd_ConfFile, "r" );
@@ -938,9 +944,37 @@ Read_Config(bool TestOnly, bool IsStarting)
 #endif
 
        Read_Config_File(NGIRCd_ConfFile, fd);
-
-       /* Close configuration file */
-       fclose( fd );
+       fclose(fd);
+
+       if (Conf_IncludeDir[0]) {
+               /* Include further configuration files, if any */
+               dh = opendir(Conf_IncludeDir);
+               if (dh) {
+                       while ((entry = readdir(dh)) != NULL) {
+                               ptr = strrchr(entry->d_name, '.');
+                               if (!ptr || strcasecmp(ptr, ".conf") != 0)
+                                       continue;
+                               snprintf(file, sizeof(file), "%s/%s",
+                                        Conf_IncludeDir, entry->d_name);
+                               if (TestOnly)
+                                       Config_Error(LOG_INFO,
+                                                    "Reading configuration from \"%s\" ...",
+                                                    file);
+                               fd = fopen(file, "r");
+                               if (fd) {
+                                       Read_Config_File(file, fd);
+                                       fclose(fd);
+                               } else
+                                       Config_Error(LOG_ALERT,
+                                                    "Can't read configuration \"%s\": %s",
+                                                    file, strerror(errno));
+                       }
+                       closedir(dh);
+               } else
+                       Config_Error(LOG_ALERT,
+                                    "Can't open include directory \"%s\": %s",
+                                    Conf_IncludeDir, strerror(errno));
+       }
 
        /* Check if there is still a server to add */
        if( New_Server.name[0] ) {
@@ -999,6 +1033,7 @@ static void Read_Config_File(const char *File, FILE *fd)
        size_t count;
 
        /* Read configuration file */
+       section[0] = '\0';
        while (true) {
                if (!fgets(str, LINE_LEN, fd))
                        break;
@@ -1648,6 +1683,12 @@ Handle_OPTIONS(const char *File, int Line, char *Var, char *Arg)
                WarnIdent(Line);
                return;
        }
+       if (strcasecmp(Var, "IncludeDir") == 0) {
+               len = strlcpy(Conf_IncludeDir, Arg, sizeof(Conf_IncludeDir));
+               if (len >= sizeof(Conf_IncludeDir))
+                       Config_Error_TooLong(File, Line, Var);
+               return;
+       }
        if (strcasecmp(Var, "MorePrivacy") == 0) {
                Conf_MorePrivacy = Check_ArgIsTrue(Arg);
                return;