This seemed to disappear into the void first time, so i'll try resending
it from pine rather than thunderbird...

---------- Forwarded message ----------
Date: Thu, 22 Apr 2004 11:31:56 +0100
From: Matthew Hodgson <[EMAIL PROTECTED]>
To: [EMAIL PROTECTED]
Subject: libconfig patch for including files

Hi,

I have a slightly strange requirement for being able to include additional
config files in my /etc/imapd.conf.  The motivation is not because a ~60 line
imapd.conf needs abstraction to be manageable, but because includes allow
sensitive information such as plaintext MySQL passwords to reside in a
standalone file, allowing the rest of the config to be checked into a
relatively public CVS repository.  The desired effect is to go from:

sasl_sql_user: cyrus
sasl_sql_passwd: secret

to

sasl_sql_user: cyrus
include: /etc/imapd-passwd.conf

where

% cat /etc/imapd-passwd.conf
# we keep this in here to prevent it from getting checked into CVS.

sasl_sql_passwd: secret


To this end, i've shuffled the libconfig code around slightly; patch against CVS head attached for constructive abuse, and the hope that someone else might find it useful.

cheers,

Matthew.

--
______________________________________________________________
Matthew Hodgson   [EMAIL PROTECTED]   Tel: +44 845 6667778
                Systems Analyst, MX Telecom Ltd.
Index: libconfig.c
===================================================================
RCS file: /cvs/src/cyrus/lib/libconfig.c,v
retrieving revision 1.7
diff -u -r1.7 libconfig.c
--- libconfig.c 29 Dec 2003 20:22:55 -0000      1.7
+++ libconfig.c 22 Apr 2004 10:04:28 -0000
@@ -79,6 +79,9 @@
 extern void fatal(const char *fatal_message, int fatal_code)
    __attribute__ ((noreturn));
 
+/* prototype to allow for sane function ordering */
+void config_read_file(const char *filename);
+
 const char *config_getstring(enum imapopt opt)
 {
     assert(opt > IMAPOPT_ZERO && opt < IMAPOPT_LAST);
@@ -149,6 +152,98 @@
 
 void config_read(const char *alt_config)
 {
+    enum opttype opt = IMAPOPT_ZERO;
+    char buf[4096];
+    char *p;
+
+    /* xxx this is leaked, this may be able to be better in 2.2 (cyrus_done) */
+    if(alt_config) config_filename = xstrdup(alt_config);
+    else config_filename = xstrdup(CONFIG_FILENAME);
+
+    if(!construct_hash_table(&confighash, CONFIGHASHSIZE, 1)) {
+       fatal("could not construct configuration hash table", EC_CONFIG);
+    }
+
+    config_read_file(config_filename);
+
+    /* Check configdirectory config option */
+    if (!config_dir) {
+       fatal("configdirectory option not specified in configuration file",
+             EC_CONFIG);
+    }
+
+    /* Scan options to see if we need to replace {configdirectory} */
+    /* xxx need to scan overflow options as well! */
+    for(opt = IMAPOPT_ZERO; opt < IMAPOPT_LAST; opt++) {
+       if(!imapopts[opt].val.s ||
+          imapopts[opt].t != OPT_STRING ||
+          opt == IMAPOPT_CONFIGDIRECTORY) {
+           /* Skip options that have a NULL value, aren't strings, or
+            * are the configdirectory option */
+           continue;
+       }
+       
+       /* We use some magic numbers here,
+        * 17 is the length of "{configdirectory}",
+        * 16 is one less than that length, so that the replacement string
+        *    that is malloced has room for the '\0' */
+       if(!strncasecmp(imapopts[opt].val.s,"{configdirectory}",17)) {
+           const char *str = imapopts[opt].val.s;
+           char *newstring =
+               xmalloc(strlen(config_dir) + strlen(str) - 16);
+           char *freeme = NULL;
+           
+           /* we need to replace this string, will we need to free
+            * the current value?  -- only if we've actually seen it in
+            * the config file. */
+           if(imapopts[opt].seen)
+               freeme = (char *)str;
+
+           /* Build replacement string from configdirectory option */
+           strcpy(newstring, config_dir);
+           strcat(newstring, str + 17);
+
+           imapopts[opt].val.s = newstring;
+
+           if(freeme) free(freeme);
+       }
+    }
+
+    /* Look up default partition */
+    config_defpartition = config_getstring(IMAPOPT_DEFAULTPARTITION);
+    for (p = (char *)config_defpartition; *p; p++) {
+       if (!isalnum((unsigned char) *p))
+         fatal("defaultpartition option contains non-alphanumeric character",
+               EC_CONFIG);
+       if (isupper((unsigned char) *p)) *p = tolower((unsigned char) *p);
+    }
+    if ((config_need_data & CONFIG_NEED_PARTITION_DATA) &&
+       (!config_defpartition || !config_partitiondir(config_defpartition))) {
+       snprintf(buf, sizeof(buf),
+               "partition-%s option not specified in configuration file",
+               config_defpartition);
+       fatal(buf, EC_CONFIG);
+    }
+
+    /* look up mailbox hashing */
+    config_hashimapspool = config_getswitch(IMAPOPT_HASHIMAPSPOOL);
+
+    /* are we supporting virtual domains?  */
+    config_virtdomains = config_getenum(IMAPOPT_VIRTDOMAINS);
+    config_defdomain = config_getstring(IMAPOPT_DEFAULTDOMAIN);
+
+    /* look up the hostname we should present to the user */
+    config_servername = config_getstring(IMAPOPT_SERVERNAME);
+    if (!config_servername) {
+       config_servername = xmalloc(sizeof(char) * 256);
+       gethostname((char *) config_servername, 256);
+    }
+
+    config_mupdate_server = config_getstring(IMAPOPT_MUPDATE_SERVER);
+}
+
+void config_read_file(const char *filename)
+{
     FILE *infile;
     enum opttype opt = IMAPOPT_ZERO;
     int lineno = 0;
@@ -157,24 +252,16 @@
     int service_specific;
     int idlen = (config_ident ? strlen(config_ident) : 0);
 
-    if(!construct_hash_table(&confighash, CONFIGHASHSIZE, 1)) {
-       fatal("could not construct configuration hash table", EC_CONFIG);
-    }
-
-    /* xxx this is leaked, this may be able to be better in 2.2 (cyrus_done) */
-    if(alt_config) config_filename = xstrdup(alt_config);
-    else config_filename = xstrdup(CONFIG_FILENAME);
-
     /* read in config file */
-    infile = fopen(config_filename, "r");
+    infile = fopen(filename, "r");
     if (!infile) {
        strlcpy(buf, CYRUS_PATH, sizeof(buf));
-       strlcat(buf, config_filename, sizeof(buf));
+       strlcat(buf, filename, sizeof(buf));
        infile = fopen(buf, "r");
     }
     if (!infile) {
        snprintf(buf, sizeof(buf), "can't open configuration file %s: %s",
-                config_filename, error_message(errno));
+                filename, error_message(errno));
        fatal(buf, EC_CONFIG);
     }
     
@@ -194,8 +281,8 @@
        }
        if (*p != ':') {
            snprintf(errbuf, sizeof(errbuf),
-                   "invalid option name on line %d of configuration file",
-                   lineno);
+                   "invalid option name on line %d of configuration file %s",
+                   lineno, filename);
            fatal(errbuf, EC_CONFIG);
        }
        *p++ = '\0';
@@ -216,6 +303,15 @@
        
        srvkey = NULL;
 
+       /* Look for an include statement */
+       if (!strcasecmp(key, "include")) {
+           char *inc_filename;
+           inc_filename = xstrdup(p);
+           config_read_file(inc_filename);
+           free(inc_filename);
+           continue;           
+       }
+
        /* Find if there is a <service>_ prefix */
        if(config_ident && !strncasecmp(key, config_ident, idlen) 
           && key[idlen] == '_') {
@@ -387,79 +483,4 @@
        }
     }
     fclose(infile);
-
-    /* Check configdirectory config option */
-    if (!config_dir) {
-       fatal("configdirectory option not specified in configuration file",
-             EC_CONFIG);
-    }
-
-    /* Scan options to see if we need to replace {configdirectory} */
-    /* xxx need to scan overflow options as well! */
-    for(opt = IMAPOPT_ZERO; opt < IMAPOPT_LAST; opt++) {
-       if(!imapopts[opt].val.s ||
-          imapopts[opt].t != OPT_STRING ||
-          opt == IMAPOPT_CONFIGDIRECTORY) {
-           /* Skip options that have a NULL value, aren't strings, or
-            * are the configdirectory option */
-           continue;
-       }
-       
-       /* We use some magic numbers here,
-        * 17 is the length of "{configdirectory}",
-        * 16 is one less than that length, so that the replacement string
-        *    that is malloced has room for the '\0' */
-       if(!strncasecmp(imapopts[opt].val.s,"{configdirectory}",17)) {
-           const char *str = imapopts[opt].val.s;
-           char *newstring =
-               xmalloc(strlen(config_dir) + strlen(str) - 16);
-           char *freeme = NULL;
-           
-           /* we need to replace this string, will we need to free
-            * the current value?  -- only if we've actually seen it in
-            * the config file. */
-           if(imapopts[opt].seen)
-               freeme = (char *)str;
-
-           /* Build replacement string from configdirectory option */
-           strcpy(newstring, config_dir);
-           strcat(newstring, str + 17);
-
-           imapopts[opt].val.s = newstring;
-
-           if(freeme) free(freeme);
-       }
-    }
-
-    /* Look up default partition */
-    config_defpartition = config_getstring(IMAPOPT_DEFAULTPARTITION);
-    for (p = (char *)config_defpartition; *p; p++) {
-       if (!isalnum((unsigned char) *p))
-         fatal("defaultpartition option contains non-alphanumeric character",
-               EC_CONFIG);
-       if (isupper((unsigned char) *p)) *p = tolower((unsigned char) *p);
-    }
-    if ((config_need_data & CONFIG_NEED_PARTITION_DATA) &&
-       (!config_defpartition || !config_partitiondir(config_defpartition))) {
-       snprintf(buf, sizeof(buf),
-               "partition-%s option not specified in configuration file",
-               config_defpartition);
-       fatal(buf, EC_CONFIG);
-    }
-
-    /* look up mailbox hashing */
-    config_hashimapspool = config_getswitch(IMAPOPT_HASHIMAPSPOOL);
-
-    /* are we supporting virtual domains?  */
-    config_virtdomains = config_getenum(IMAPOPT_VIRTDOMAINS);
-    config_defdomain = config_getstring(IMAPOPT_DEFAULTDOMAIN);
-
-    /* look up the hostname we should present to the user */
-    config_servername = config_getstring(IMAPOPT_SERVERNAME);
-    if (!config_servername) {
-       config_servername = xmalloc(sizeof(char) * 256);
-       gethostname((char *) config_servername, 256);
-    }
-
-    config_mupdate_server = config_getstring(IMAPOPT_MUPDATE_SERVER);
 }

Reply via email to