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);
}