typedef struct cf_file_t {
char const *filename;
CONF_SECTION *cs;
- bool input;
struct stat buf;
} cf_file_t;
file->filename = filename;
file->cs = cs;
- file->input = true;
if (fstat(fd, &file->buf) == 0) {
#ifdef S_IWOTH
}
/*
- * Do some checks on the file as an "input" file. i.e. one read
- * by a module.
+ * Do some checks on the file
*/
-static bool cf_file_input(CONF_SECTION *cs, char const *filename)
+static bool cf_file_check(CONF_SECTION *cs, char const *filename, bool check_perms)
{
cf_file_t *file;
CONF_DATA *cd;
file->filename = filename;
file->cs = cs;
- file->input = true;
if (stat(filename, &file->buf) < 0) {
- ERROR("Unable to open file \"%s\": %s", filename, fr_syserror(errno));
+ ERROR("Unable to check file \"%s\": %s", filename, fr_syserror(errno));
talloc_free(file);
return false;
}
+ if (!check_perms) {
+ talloc_free(file);
+ return true;
+ }
+
#ifdef S_IWOTH
if ((file->buf.st_mode & S_IWOTH) != 0) {
ERROR("Configuration file %s is globally writable. "
* The file changed, we'll need to re-read it.
*/
if (buf.st_mtime != file->buf.st_mtime) {
- if (!file->input) {
- cb->rcode |= CF_FILE_CONFIG;
- } else {
- (void) cb->callback(cb->modules, file->cs);
+
+ if (cb->callback(cb->modules, file->cs)) {
cb->rcode |= CF_FILE_MODULE;
+ DEBUG3("HUP: Changed module file %s", file->filename);
+ } else {
+ DEBUG3("HUP: Changed config file %s", file->filename);
+ cb->rcode |= CF_FILE_CONFIG;
}
}
ERROR("%s[%d]: Reference \"%s\" type is invalid", cf, *lineno, input);
return NULL;
}
- } else if (memcmp(ptr, "$ENV{", 5) == 0) {
+ } else if (strncmp(ptr, "$ENV{", 5) == 0) {
char *env;
ptr += 5;
int cf_item_parse(CONF_SECTION *cs, char const *name, unsigned int type, void *data, char const *dflt)
{
int rcode;
- bool deprecated, required, attribute, secret, file_input, cant_be_empty, tmpl, multi;
+ bool deprecated, required, attribute, secret, file_input, cant_be_empty, tmpl, multi, file_exists;
char **q;
char const *value;
CONF_PAIR *cp = NULL;
fr_ipaddr_t *ipaddr;
char buffer[8192];
- CONF_ITEM *c_item = &cs->item;
+ CONF_ITEM *c_item;
if (!cs) return -1;
+ c_item = &cs->item;
+
deprecated = (type & PW_TYPE_DEPRECATED);
required = (type & PW_TYPE_REQUIRED);
attribute = (type & PW_TYPE_ATTRIBUTE);
secret = (type & PW_TYPE_SECRET);
file_input = (type == PW_TYPE_FILE_INPUT); /* check, not and */
+ file_exists = (type == PW_TYPE_FILE_EXISTS); /* check, not and */
cant_be_empty = (type & PW_TYPE_NOT_EMPTY);
tmpl = (type & PW_TYPE_TMPL);
multi = (type & PW_TYPE_MULTI);
*/
} else {
CONF_PAIR *next = cp;
+
value = cp->value;
cp->parsed = true;
c_item = &cp->item;
- /*
- * @fixme We should actually validate
- * the value of the pairs too
- */
- if (multi) while ((next = cf_pair_find_next(cs, next, name))) {
- next->parsed = true;
- }
-
if (deprecated) {
cf_log_err(c_item, "Configuration item \"%s\" is deprecated", name);
-
return -2;
}
+
+ /*
+ * A quick check to see if the next item is the same.
+ */
+ if (!multi && cp->item.next && (cp->item.next->type == CONF_ITEM_PAIR)) {
+ next = cf_item_to_pair(cp->item.next);
+
+ if (strcmp(next->attr, name) == 0) {
+ WARN("%s[%d]: Ignoring duplicate configuration item '%s'",
+ next->item.filename ? next->item.filename : "unknown",
+ next->item.lineno, name);
+ }
+ }
+
+ if (multi) {
+ while ((next = cf_pair_find_next(cs, next, name)) != NULL) {
+ /*
+ * @fixme We should actually validate
+ * the value of the pairs too
+ */
+ next->parsed = true;
+ };
+ }
}
if (!value) {
if (required) {
- is_required:
cf_log_err(c_item, "Configuration item \"%s\" must have a value", name);
return -1;
}
}
- if (required && !value) goto is_required;
if (cant_be_empty && (value[0] == '\0')) goto cant_be_empty;
if (attribute) {
* to be caught as early as possible, during
* server startup.
*/
- if (*q && file_input && !cf_file_input(cs, *q)) {
+ if (*q && file_input && !cf_file_check(cs, *q, true)) {
+ return -1;
+ }
+
+ if (*q && file_exists && !cf_file_check(cs, *q, false)) {
return -1;
}
break;
(variables[i + 1].data == variables[i].data)) {
cf_log_err(&(cs->item), "Replace \"%s\" with \"%s\"", variables[i].name,
variables[i + 1].name);
+ } else {
+ cf_log_err(&(cs->item), "Cannot use deprecated configuration item \"%s\"", variables[i].name);
}
goto finish;
}
{
CONF_DATA mycd;
CONF_DATA *cd;
+ CONF_ITEM *ci, *it;
void *data;
if (!cs || !name) return NULL;
cd = rbtree_finddata(cs->data_tree, &mycd);
if (!cd) return NULL;
+ ci = cf_data_to_item(cd);
+ if (cs->children == ci) {
+ cs->children = ci->next;
+ if (cs->tail == ci) cs->tail = NULL;
+ } else {
+ for (it = cs->children; it; it = it->next) {
+ if (it->next == ci) {
+ it->next = ci->next;
+ if (cs->tail == ci) cs->tail = it;
+ break;
+ }
+ }
+ }
+
talloc_set_destructor(cd, NULL); /* Disarm the destructor */
rbtree_deletebydata(cs->data_tree, &mycd);