int type, void *data, const char *dflt);
int cf_section_parse(CONF_SECTION *, void *base,
const CONF_PARSER *variables);
+void cf_section_parse_free(CONF_SECTION *cs, void *base);
CONF_SECTION *cf_file_read(const char *file);
int cf_file_include(const char *file, CONF_SECTION *cs);
#define RLM_TYPE_THREAD_SAFE (0 << 0)
#define RLM_TYPE_THREAD_UNSAFE (1 << 0)
#define RLM_TYPE_CHECK_CONFIG_SAFE (1 << 1)
+#define RLM_TYPE_HUP_SAFE (1 << 2)
#define RLM_MODULE_MAGIC_NUMBER ((uint32_t) (0xf4ee4ad2))
#define RLM_MODULE_INIT RLM_MODULE_MAGIC_NUMBER
int setup_modules(int, CONF_SECTION *);
int detach_modules(void);
+int module_hup(CONF_SECTION *modules);
int module_authorize(int type, REQUEST *request);
int module_authenticate(int type, REQUEST *request);
int module_preacct(REQUEST *request);
/*
* Free strings we've parsed into data structures.
*/
-static void cf_section_parse_free(void *base, const CONF_PARSER *variables)
+void cf_section_parse_free(CONF_SECTION *cs, void *base)
{
int i;
+ const CONF_PARSER *variables = cs->variables;
/*
* Don't automatically free the strings if we're being
if (!cs || !*cs) return;
- if ((*cs)->variables) {
- cf_section_parse_free((*cs)->base, (*cs)->variables);
- }
+ cf_section_parse_free(*cs, (*cs)->base);
for (ci = (*cs)->children; ci; ci = next) {
next = ci->next;
int i;
void *data;
+ cs->variables = variables; /* this doesn't hurt anything */
+
if (!cs->name2) {
DEBUG2("%.*s%s {", cs->depth, parse_spaces,
cs->name1);
DEBUG2("%.*s}", cs->depth, parse_spaces);
cs->base = base;
- cs->variables = variables;
return 0;
error:
DEBUG2("%.*s}", cs->depth, parse_spaces);
- cf_section_parse_free(base, variables);
+ cf_section_parse_free(cs, base);
return -1;
}
return 0;
}
+
+int module_hup(CONF_SECTION *modules)
+{
+ CONF_ITEM *ci;
+ CONF_SECTION *cs;
+ module_instance_t *node;
+
+ if (!modules) return 0;
+
+ /*
+ * Loop over the modules
+ */
+ for (ci=cf_item_find_next(modules, NULL);
+ ci != NULL;
+ ci=cf_item_find_next(modules, ci)) {
+ void *insthandle = NULL;
+ void *old_insthandle = NULL;
+
+ /*
+ * If it's not a section, ignore it.
+ */
+ if (!cf_item_is_section(ci)) continue;
+
+ cs = cf_itemtosection(ci);
+
+ node = cf_data_find(cs, "instance");
+ if (!node ||
+ ((node->entry->module->type & RLM_TYPE_HUP_SAFE) == 0)) {
+ continue;
+ }
+
+ DEBUG2(" Module: Trying to reload module \"%s\"", node->name);
+
+ if ((node->entry->module->instantiate)(cs, &insthandle) < 0) {
+ cf_log_err(cf_sectiontoitem(cs),
+ "HUP failed for module \"%s\"",
+ node->name);
+ continue;
+ }
+
+ radlog(L_INFO, " Module: Reloaded module \"%s\"", node->name);
+
+ old_insthandle = node->insthandle;
+ node->insthandle = insthandle;
+
+ cf_section_parse_free(cs, old_insthandle);
+
+ if (node->entry->module->detach) {
+ (node->entry->module->detach)(old_insthandle);
+ }
+ }
+
+ return 1;
+}
+
+
/*
* Parse the module config sections, and load
* and call each module's init() function.
* Process requests until HUP or exit.
*/
while ((rcode = radius_event_process()) == 0x80) {
- thread_pool_lock();
- /*
- * Reload anything that can safely be reloaded.
- */
- DEBUG("HUP support not available.");
-
- thread_pool_unlock();
+ module_hup(cf_section_sub_find(mainconfig.config, "modules"));
}
DEBUG("Exiting...");
module_t rlm_files = {
RLM_MODULE_INIT,
"files",
- RLM_TYPE_CHECK_CONFIG_SAFE, /* type: reserved */
+ RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE,
file_instantiate, /* instantiation */
file_detach, /* detach */
{