# for an example.
#
+ #
+ # Some modules have ordering issues. e.g. "sqlippool" uses
+ # the configuration from "sql". In that case, the "sql"
+ # module must be read off of disk before the "sqlippool".
+ # However, the directory inclusion below just reads the
+ # directory from start to finish. Which means that the
+ # modules are read off of disk randomly.
+ #
+ # As of 3.0.18, you can list individual modules *before* the
+ # directory inclusion. Those modules will be loaded first.
+ # Then, when the directory is read, those modules will be
+ # skipped and not read twice.
+ #
+# $INCLUDE mods-enabled/sql
+
#
# As of 3.0, modules are in mods-enabled/. Files matching
# the regex /[a-zA-Z0-9_.]+/ are loaded. The modules are
char *output, size_t outsize,
char const *input, bool *soft_fail);
-static int cf_file_include(CONF_SECTION *cs, char const *filename_in);
+static int cf_file_include(CONF_SECTION *cs, char const *filename_in, bool from_dir);
return 0;
}
-static FILE *cf_file_open(CONF_SECTION *cs, char const *filename)
+static int cf_file_open(CONF_SECTION *cs, char const *filename, bool from_dir, FILE **fp_p)
{
cf_file_t *file;
CONF_DATA *cd;
top = cf_top_section(cs);
cd = cf_data_find_internal(top, "filename", 0);
- if (!cd) return NULL;
+ if (!cd) return -1;
tree = cd->data;
+ /*
+ * If we're including a wildcard directory, then ignore
+ * any files the users has already explicitly loaded in
+ * that directory.
+ */
+ if (from_dir) {
+ cf_file_t my_file;
+
+ my_file.cs = cs;
+ my_file.filename = filename;
+
+ if (stat(filename, &my_file.buf) < 0) goto error;
+
+ file = rbtree_finddata(tree, &my_file);
+ if (file) return 0;
+ }
+
+ DEBUG2("including configuration file %s", filename);
+
fp = fopen(filename, "r");
if (!fp) {
+error:
ERROR("Unable to open file \"%s\": %s",
filename, fr_syserror(errno));
- return NULL;
+ return -1;
}
fd = fileno(fp);
file = talloc(tree, cf_file_t);
if (!file) {
fclose(fp);
- return NULL;
+ return -1;
}
file->filename = filename;
fclose(fp);
talloc_free(file);
- return NULL;
+ return -1;
}
#endif
}
talloc_free(file);
}
- return fp;
+ *fp_p = fp;
+ return 1;
}
/*
value, dp->d_name);
if ((stat(buf2, &stat_buf) != 0) ||
S_ISDIR(stat_buf.st_mode)) continue;
+
/*
* Read the file into the current
* configuration section.
*/
- if (cf_file_include(this, buf2) < 0) {
+ if (cf_file_include(this, buf2, true) < 0) {
closedir(dir);
return -1;
}
}
}
- if (cf_file_include(this, value) < 0) {
+ if (cf_file_include(this, value, false) < 0) {
return -1;
}
}
/*
* Include one config file in another.
*/
-static int cf_file_include(CONF_SECTION *cs, char const *filename_in)
+static int cf_file_include(CONF_SECTION *cs, char const *filename_in, bool from_dir)
{
FILE *fp;
+ int rcode;
int lineno = 0;
char const *filename;
*/
filename = talloc_strdup(cs, filename_in);
- DEBUG2("including configuration file %s", filename);
-
- fp = cf_file_open(cs, filename);
- if (!fp) return -1;
+ /*
+ * This may return "0" if we already loaded the file.
+ */
+ rcode = cf_file_open(cs, filename, from_dir, &fp);
+ if (rcode <= 0) return rcode;
if (!cs->item.filename) cs->item.filename = filename;
cf_data_add_internal(cs, "filename", tree, NULL, 0);
- if (cf_file_include(cs, filename) < 0) return -1;
+ if (cf_file_include(cs, filename, false) < 0) return -1;
/*
* Now that we've read the file, go back through it and