|
|
f92ce9 |
From 78b344ff88f488aa63ccccf464e83ad55ee9e96d Mon Sep 17 00:00:00 2001
|
|
|
f92ce9 |
From: Mark Reynolds <mreynolds@redhat.com>
|
|
|
f92ce9 |
Date: Tue, 16 Dec 2014 15:25:35 -0500
|
|
|
f92ce9 |
Subject: [PATCH 50/53] Ticket 47451 - Dynamic Plugin - various fixes
|
|
|
f92ce9 |
|
|
|
f92ce9 |
Description: The previous commit 0e0848a8385463532d53db94c0c8cae912c30eb4 on
|
|
|
f92ce9 |
master branch was wrong, and broke the other plugin tasks.
|
|
|
f92ce9 |
|
|
|
f92ce9 |
Upon further testing, some memory leaks and crashes were detected
|
|
|
f92ce9 |
and fixed:
|
|
|
f92ce9 |
|
|
|
f92ce9 |
automember.c - Fix memory leak, and PRCList corruption
|
|
|
f92ce9 |
dna.c - Fix crash caused by event context not being freed at plugin stop
|
|
|
f92ce9 |
memberof.c - pass in the correct function argument, not the pblock
|
|
|
f92ce9 |
rootdn_access.c - Fix memory leak
|
|
|
f92ce9 |
plugins/uiduniq/uid.c - Add start and close functions to properly handle plugin restarts
|
|
|
f92ce9 |
dse.c - Improve plugin restart handling, and properly handle plugin registration
|
|
|
f92ce9 |
plugin.c - Properly wait for a plugin to finish before restarting it.
|
|
|
f92ce9 |
task.c - Proprely handle the task function arguments
|
|
|
f92ce9 |
|
|
|
f92ce9 |
https://fedorahosted.org/389/ticket/47451
|
|
|
f92ce9 |
|
|
|
f92ce9 |
Reviewed by: nhosoi(Thanks!)
|
|
|
f92ce9 |
|
|
|
f92ce9 |
(cherry picked from commit ff023a48b7fc78711eed8ae11e67057597acdeb3)
|
|
|
f92ce9 |
(cherry picked from commit f17159e73ba0851599c4e50c1bf52d3d10f2711f)
|
|
|
f92ce9 |
---
|
|
|
f92ce9 |
ldap/servers/plugins/automember/automember.c | 4 +-
|
|
|
f92ce9 |
ldap/servers/plugins/dna/dna.c | 14 ++-
|
|
|
f92ce9 |
ldap/servers/plugins/memberof/memberof.c | 2 +-
|
|
|
f92ce9 |
ldap/servers/plugins/rootdn_access/rootdn_access.c | 4 +-
|
|
|
f92ce9 |
ldap/servers/plugins/schema_reload/schema_reload.c | 2 +-
|
|
|
f92ce9 |
ldap/servers/plugins/uiduniq/uid.c | 63 ++++++++----
|
|
|
f92ce9 |
ldap/servers/slapd/dse.c | 74 +++++++-------
|
|
|
f92ce9 |
ldap/servers/slapd/plugin.c | 110 ++++++++++++---------
|
|
|
f92ce9 |
ldap/servers/slapd/task.c | 10 +-
|
|
|
f92ce9 |
9 files changed, 161 insertions(+), 122 deletions(-)
|
|
|
f92ce9 |
|
|
|
f92ce9 |
diff --git a/ldap/servers/plugins/automember/automember.c b/ldap/servers/plugins/automember/automember.c
|
|
|
f92ce9 |
index c443a65..6a8fd22 100644
|
|
|
f92ce9 |
--- a/ldap/servers/plugins/automember/automember.c
|
|
|
f92ce9 |
+++ b/ldap/servers/plugins/automember/automember.c
|
|
|
f92ce9 |
@@ -406,7 +406,6 @@ automember_close(Slapi_PBlock * pb)
|
|
|
f92ce9 |
automember_task_add_map_entries);
|
|
|
f92ce9 |
|
|
|
f92ce9 |
automember_delete_config();
|
|
|
f92ce9 |
- slapi_ch_free((void **)&g_automember_config);
|
|
|
f92ce9 |
slapi_sdn_free(&_PluginDN);
|
|
|
f92ce9 |
slapi_sdn_free(&_ConfigAreaDN);
|
|
|
f92ce9 |
slapi_destroy_rwlock(g_automember_config_lock);
|
|
|
f92ce9 |
@@ -449,6 +448,8 @@ automember_load_config()
|
|
|
f92ce9 |
/* Clear out any old config. */
|
|
|
f92ce9 |
automember_config_write_lock();
|
|
|
f92ce9 |
automember_delete_config();
|
|
|
f92ce9 |
+ g_automember_config = (PRCList *)slapi_ch_calloc(1, sizeof(struct configEntry));
|
|
|
f92ce9 |
+ PR_INIT_CLIST(g_automember_config);
|
|
|
f92ce9 |
|
|
|
f92ce9 |
search_pb = slapi_pblock_new();
|
|
|
f92ce9 |
|
|
|
f92ce9 |
@@ -866,6 +867,7 @@ automember_delete_config()
|
|
|
f92ce9 |
list = PR_LIST_HEAD(g_automember_config);
|
|
|
f92ce9 |
automember_delete_configEntry(list);
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
+ slapi_ch_free((void **)&g_automember_config);
|
|
|
f92ce9 |
|
|
|
f92ce9 |
return;
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
diff --git a/ldap/servers/plugins/dna/dna.c b/ldap/servers/plugins/dna/dna.c
|
|
|
f92ce9 |
index 75edca8..ded0bbb 100644
|
|
|
f92ce9 |
--- a/ldap/servers/plugins/dna/dna.c
|
|
|
f92ce9 |
+++ b/ldap/servers/plugins/dna/dna.c
|
|
|
f92ce9 |
@@ -202,6 +202,7 @@ static char *hostname = NULL;
|
|
|
f92ce9 |
static char *portnum = NULL;
|
|
|
f92ce9 |
static char *secureportnum = NULL;
|
|
|
f92ce9 |
|
|
|
f92ce9 |
+static Slapi_Eq_Context eq_ctx = {0};
|
|
|
f92ce9 |
|
|
|
f92ce9 |
/**
|
|
|
f92ce9 |
* server struct for shared ranges
|
|
|
f92ce9 |
@@ -708,6 +709,7 @@ dna_close(Slapi_PBlock * pb)
|
|
|
f92ce9 |
slapi_log_error(SLAPI_LOG_TRACE, DNA_PLUGIN_SUBSYSTEM,
|
|
|
f92ce9 |
"--> dna_close\n");
|
|
|
f92ce9 |
|
|
|
f92ce9 |
+ slapi_eq_cancel(eq_ctx);
|
|
|
f92ce9 |
dna_delete_config(NULL);
|
|
|
f92ce9 |
slapi_ch_free((void **)&dna_global_config);
|
|
|
f92ce9 |
slapi_destroy_rwlock(g_dna_cache_lock);
|
|
|
f92ce9 |
@@ -869,7 +871,7 @@ dna_load_plugin_config(Slapi_PBlock *pb, int use_eventq)
|
|
|
f92ce9 |
* starting up would cause the change to not
|
|
|
f92ce9 |
* get changelogged. */
|
|
|
f92ce9 |
time(&now;;
|
|
|
f92ce9 |
- slapi_eq_once(dna_update_config_event, NULL, now + 30);
|
|
|
f92ce9 |
+ eq_ctx = slapi_eq_once(dna_update_config_event, NULL, now + 30);
|
|
|
f92ce9 |
} else {
|
|
|
f92ce9 |
dna_update_config_event(0, NULL);
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
@@ -2404,7 +2406,7 @@ static int dna_get_next_value(struct configEntry *config_entry,
|
|
|
f92ce9 |
} else {
|
|
|
f92ce9 |
/* dna_first_free_value() failed for some unknown reason */
|
|
|
f92ce9 |
slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM,
|
|
|
f92ce9 |
- "dna_get_next_value: failed to allocate a new ID!!\n");
|
|
|
f92ce9 |
+ "dna_get_next_value: failed to allocate a new ID!! (set(%d) (max: %d)\n",setval,config_entry->maxval);
|
|
|
f92ce9 |
goto done;
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
@@ -3401,7 +3403,7 @@ _dna_pre_op_add(Slapi_PBlock *pb, Slapi_Entry *e, char **errstr)
|
|
|
f92ce9 |
ret = dna_first_free_value(config_entry, &setval);
|
|
|
f92ce9 |
if (LDAP_SUCCESS != ret){
|
|
|
f92ce9 |
slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM,
|
|
|
f92ce9 |
- "dna_pre_op: failed to allocate a new ID\n");
|
|
|
f92ce9 |
+ "dna_pre_op: failed to allocate a new ID 1\n");
|
|
|
f92ce9 |
/* Set an error string to be returned to the client. */
|
|
|
f92ce9 |
*errstr = slapi_ch_smprintf("Allocation of a new value for range"
|
|
|
f92ce9 |
" %s failed! Unable to proceed.",
|
|
|
f92ce9 |
@@ -3412,7 +3414,9 @@ _dna_pre_op_add(Slapi_PBlock *pb, Slapi_Entry *e, char **errstr)
|
|
|
f92ce9 |
} else {
|
|
|
f92ce9 |
/* dna_first_free_value() failed for some unknown reason */
|
|
|
f92ce9 |
slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM,
|
|
|
f92ce9 |
- "dna_pre_op: failed to allocate a new ID!!\n");
|
|
|
f92ce9 |
+ "dna_pre_op: failed to allocate a new ID!! 2\n");
|
|
|
f92ce9 |
+ slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM,
|
|
|
f92ce9 |
+ "dna_get_next_value: failed to allocate a new ID!! (set(%d) (max: %d)\n",setval,config_entry->maxval);
|
|
|
f92ce9 |
/* Set an error string to be returned to the client. */
|
|
|
f92ce9 |
*errstr = slapi_ch_smprintf("Allocation of a new value for range"
|
|
|
f92ce9 |
" %s failed! Unable to proceed.",
|
|
|
f92ce9 |
@@ -3678,6 +3682,8 @@ _dna_pre_op_modify(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Mods *smods, char **e
|
|
|
f92ce9 |
/* dna_first_free_value() failed for some unknown reason */
|
|
|
f92ce9 |
slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM,
|
|
|
f92ce9 |
"dna_pre_op: failed to allocate a new ID!!\n");
|
|
|
f92ce9 |
+ slapi_log_error(SLAPI_LOG_FATAL, DNA_PLUGIN_SUBSYSTEM,
|
|
|
f92ce9 |
+ "dna_get_next_value: failed to allocate a new ID!! (set(%d) (max: %d)\n",setval,config_entry->maxval);
|
|
|
f92ce9 |
/* Set an error string to be returned to the client. */
|
|
|
f92ce9 |
*errstr = slapi_ch_smprintf("Allocation of a new value for range"
|
|
|
f92ce9 |
" %s failed! Unable to proceed.",
|
|
|
f92ce9 |
diff --git a/ldap/servers/plugins/memberof/memberof.c b/ldap/servers/plugins/memberof/memberof.c
|
|
|
f92ce9 |
index cb4ef75..bfa733a 100644
|
|
|
f92ce9 |
--- a/ldap/servers/plugins/memberof/memberof.c
|
|
|
f92ce9 |
+++ b/ldap/servers/plugins/memberof/memberof.c
|
|
|
f92ce9 |
@@ -2764,7 +2764,7 @@ int memberof_task_add(Slapi_PBlock *pb, Slapi_Entry *e,
|
|
|
f92ce9 |
mytaskdata->bind_dn = slapi_ch_strdup(bind_dn);
|
|
|
f92ce9 |
|
|
|
f92ce9 |
/* allocate new task now */
|
|
|
f92ce9 |
- task = slapi_plugin_new_task(slapi_entry_get_ndn(e), pb);
|
|
|
f92ce9 |
+ task = slapi_plugin_new_task(slapi_entry_get_ndn(e), arg);
|
|
|
f92ce9 |
|
|
|
f92ce9 |
/* register our destructor for cleaning up our private data */
|
|
|
f92ce9 |
slapi_task_set_destructor_fn(task, memberof_task_destructor);
|
|
|
f92ce9 |
diff --git a/ldap/servers/plugins/rootdn_access/rootdn_access.c b/ldap/servers/plugins/rootdn_access/rootdn_access.c
|
|
|
f92ce9 |
index 9122f9b..3045e9f 100644
|
|
|
f92ce9 |
--- a/ldap/servers/plugins/rootdn_access/rootdn_access.c
|
|
|
f92ce9 |
+++ b/ldap/servers/plugins/rootdn_access/rootdn_access.c
|
|
|
f92ce9 |
@@ -217,7 +217,7 @@ rootdn_close(Slapi_PBlock *pb)
|
|
|
f92ce9 |
slapi_ch_array_free(hosts);
|
|
|
f92ce9 |
slapi_ch_array_free(hosts_to_deny);
|
|
|
f92ce9 |
slapi_ch_array_free(ips);
|
|
|
f92ce9 |
- slapi_ch_array_free(ips);
|
|
|
f92ce9 |
+ slapi_ch_array_free(ips_to_deny);
|
|
|
f92ce9 |
|
|
|
f92ce9 |
return 0;
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
@@ -416,6 +416,8 @@ rootdn_load_config(Slapi_PBlock *pb)
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
} else {
|
|
|
f92ce9 |
/* failed to get the plugin entry */
|
|
|
f92ce9 |
+ slapi_log_error(SLAPI_LOG_FATAL, ROOTDN_PLUGIN_SUBSYSTEM, "rootdn_load_config: "
|
|
|
f92ce9 |
+ "Failed to get plugin entry\n");
|
|
|
f92ce9 |
result = -1;
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
|
|
|
f92ce9 |
diff --git a/ldap/servers/plugins/schema_reload/schema_reload.c b/ldap/servers/plugins/schema_reload/schema_reload.c
|
|
|
f92ce9 |
index 3ff4c4d..b1a5bb8 100644
|
|
|
f92ce9 |
--- a/ldap/servers/plugins/schema_reload/schema_reload.c
|
|
|
f92ce9 |
+++ b/ldap/servers/plugins/schema_reload/schema_reload.c
|
|
|
f92ce9 |
@@ -273,7 +273,7 @@ schemareload_add(Slapi_PBlock *pb, Slapi_Entry *e,
|
|
|
f92ce9 |
schemadir = fetch_attr(e, "schemadir", NULL);
|
|
|
f92ce9 |
|
|
|
f92ce9 |
/* allocate new task now */
|
|
|
f92ce9 |
- task = slapi_plugin_new_task(slapi_entry_get_ndn(e), pb);
|
|
|
f92ce9 |
+ task = slapi_plugin_new_task(slapi_entry_get_ndn(e), arg);
|
|
|
f92ce9 |
if (task == NULL) {
|
|
|
f92ce9 |
slapi_log_error(SLAPI_LOG_FATAL, "schemareload", "unable to allocate new task!\n");
|
|
|
f92ce9 |
*returncode = LDAP_OPERATIONS_ERROR;
|
|
|
f92ce9 |
diff --git a/ldap/servers/plugins/uiduniq/uid.c b/ldap/servers/plugins/uiduniq/uid.c
|
|
|
f92ce9 |
index 07ff0ec..f37ab8c 100644
|
|
|
f92ce9 |
--- a/ldap/servers/plugins/uiduniq/uid.c
|
|
|
f92ce9 |
+++ b/ldap/servers/plugins/uiduniq/uid.c
|
|
|
f92ce9 |
@@ -1265,6 +1265,38 @@ preop_modrdn(Slapi_PBlock *pb)
|
|
|
f92ce9 |
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
|
|
|
f92ce9 |
+static int
|
|
|
f92ce9 |
+uiduniq_start(Slapi_PBlock *pb)
|
|
|
f92ce9 |
+{
|
|
|
f92ce9 |
+ Slapi_Entry *plugin_entry = NULL;
|
|
|
f92ce9 |
+ struct attr_uniqueness_config *config = NULL;
|
|
|
f92ce9 |
+
|
|
|
f92ce9 |
+ if (slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &plugin_entry) == 0){
|
|
|
f92ce9 |
+ /* load the config into the config list */
|
|
|
f92ce9 |
+ if ((config = uniqueness_entry_to_config(pb, plugin_entry)) == NULL) {
|
|
|
f92ce9 |
+ return SLAPI_PLUGIN_FAILURE;
|
|
|
f92ce9 |
+ }
|
|
|
f92ce9 |
+ slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, (void*) config);
|
|
|
f92ce9 |
+ }
|
|
|
f92ce9 |
+
|
|
|
f92ce9 |
+ return 0;
|
|
|
f92ce9 |
+}
|
|
|
f92ce9 |
+
|
|
|
f92ce9 |
+static int
|
|
|
f92ce9 |
+uiduniq_close(Slapi_PBlock *pb)
|
|
|
f92ce9 |
+{
|
|
|
f92ce9 |
+ Slapi_Entry *plugin_entry = NULL;
|
|
|
f92ce9 |
+ struct attr_uniqueness_config *config = NULL;
|
|
|
f92ce9 |
+
|
|
|
f92ce9 |
+ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &config);
|
|
|
f92ce9 |
+ if (config) {
|
|
|
f92ce9 |
+ slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, NULL);
|
|
|
f92ce9 |
+ free_uniqueness_config(config);
|
|
|
f92ce9 |
+ slapi_ch_free((void **) &config);
|
|
|
f92ce9 |
+ }
|
|
|
f92ce9 |
+ return 0;
|
|
|
f92ce9 |
+}
|
|
|
f92ce9 |
+
|
|
|
f92ce9 |
/* ------------------------------------------------------------ */
|
|
|
f92ce9 |
/*
|
|
|
f92ce9 |
* Initialize the plugin
|
|
|
f92ce9 |
@@ -1307,13 +1339,6 @@ NSUniqueAttr_Init(Slapi_PBlock *pb)
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
slapi_ch_free_string(&plugin_type);
|
|
|
f92ce9 |
|
|
|
f92ce9 |
- /* load the config into the config list */
|
|
|
f92ce9 |
- if ((config = uniqueness_entry_to_config(pb, plugin_entry)) == NULL) {
|
|
|
f92ce9 |
- err = SLAPI_PLUGIN_FAILURE;
|
|
|
f92ce9 |
- break;
|
|
|
f92ce9 |
- }
|
|
|
f92ce9 |
- slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, (void*) config);
|
|
|
f92ce9 |
-
|
|
|
f92ce9 |
/* Provide descriptive information */
|
|
|
f92ce9 |
err = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
|
|
|
f92ce9 |
(void*)&pluginDesc);
|
|
|
f92ce9 |
@@ -1329,30 +1354,26 @@ NSUniqueAttr_Init(Slapi_PBlock *pb)
|
|
|
f92ce9 |
err = slapi_pblock_set(pb, premdn, (void*)preop_modrdn);
|
|
|
f92ce9 |
if (err) break;
|
|
|
f92ce9 |
|
|
|
f92ce9 |
+ err = slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, (void *) uiduniq_start);
|
|
|
f92ce9 |
+ if (err) break;
|
|
|
f92ce9 |
+
|
|
|
f92ce9 |
+ err = slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, (void *) uiduniq_close);
|
|
|
f92ce9 |
+ if (err) break;
|
|
|
f92ce9 |
+
|
|
|
f92ce9 |
+
|
|
|
f92ce9 |
END
|
|
|
f92ce9 |
|
|
|
f92ce9 |
if (err) {
|
|
|
f92ce9 |
- slapi_log_error(SLAPI_LOG_PLUGIN, "NSUniqueAttr_Init",
|
|
|
f92ce9 |
- "Error: %d\n", err);
|
|
|
f92ce9 |
- if (config) {
|
|
|
f92ce9 |
- slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, NULL);
|
|
|
f92ce9 |
- free_uniqueness_config(config);
|
|
|
f92ce9 |
- slapi_ch_free((void **) &config);
|
|
|
f92ce9 |
- }
|
|
|
f92ce9 |
+ slapi_log_error(SLAPI_LOG_PLUGIN, "NSUniqueAttr_Init", "Error: %d\n", err);
|
|
|
f92ce9 |
err = -1;
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
else
|
|
|
f92ce9 |
- slapi_log_error(SLAPI_LOG_PLUGIN, "NSUniqueAttr_Init",
|
|
|
f92ce9 |
- "plugin loaded\n");
|
|
|
f92ce9 |
+ slapi_log_error(SLAPI_LOG_PLUGIN, "NSUniqueAttr_Init", "plugin loaded\n");
|
|
|
f92ce9 |
|
|
|
f92ce9 |
return err;
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
|
|
|
f92ce9 |
-int
|
|
|
f92ce9 |
-uidunique_init(Slapi_PBlock *pb)
|
|
|
f92ce9 |
-{
|
|
|
f92ce9 |
- return NSUniqueAttr_Init(pb);
|
|
|
f92ce9 |
-}
|
|
|
f92ce9 |
+
|
|
|
f92ce9 |
|
|
|
f92ce9 |
|
|
|
f92ce9 |
/* ------------------------------------------------------------ */
|
|
|
f92ce9 |
diff --git a/ldap/servers/slapd/dse.c b/ldap/servers/slapd/dse.c
|
|
|
f92ce9 |
index fc5f492..f0ce255 100644
|
|
|
f92ce9 |
--- a/ldap/servers/slapd/dse.c
|
|
|
f92ce9 |
+++ b/ldap/servers/slapd/dse.c
|
|
|
f92ce9 |
@@ -1827,6 +1827,7 @@ dse_modify(Slapi_PBlock *pb) /* JCM There should only be one exit point from thi
|
|
|
f92ce9 |
int retval = -1;
|
|
|
f92ce9 |
int need_be_postop = 0;
|
|
|
f92ce9 |
int plugin_started = 0;
|
|
|
f92ce9 |
+ int internal_op = 0;
|
|
|
f92ce9 |
|
|
|
f92ce9 |
PR_ASSERT(pb);
|
|
|
f92ce9 |
if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &pdse ) < 0 ||
|
|
|
f92ce9 |
@@ -1843,6 +1844,8 @@ dse_modify(Slapi_PBlock *pb) /* JCM There should only be one exit point from thi
|
|
|
f92ce9 |
return retval;
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
|
|
|
f92ce9 |
+ internal_op = operation_is_flag_set(pb->pb_op, OP_FLAG_INTERNAL);
|
|
|
f92ce9 |
+
|
|
|
f92ce9 |
/* Find the entry we are about to modify. */
|
|
|
f92ce9 |
ec = dse_get_entry_copy(pdse, sdn, DSE_USE_LOCK);
|
|
|
f92ce9 |
if ( ec == NULL ) {
|
|
|
f92ce9 |
@@ -2039,20 +2042,22 @@ dse_modify(Slapi_PBlock *pb) /* JCM There should only be one exit point from thi
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
/*
|
|
|
f92ce9 |
- * Perform postop plugin configuration changes
|
|
|
f92ce9 |
+ * Perform postop plugin configuration changes unless this is an internal operation
|
|
|
f92ce9 |
*/
|
|
|
f92ce9 |
- if(returncode == LDAP_SUCCESS){
|
|
|
f92ce9 |
- dse_post_modify_plugin(ec, ecc, mods);
|
|
|
f92ce9 |
- } else if(plugin_started){
|
|
|
f92ce9 |
- if(plugin_started == 1){
|
|
|
f92ce9 |
- /* the op failed, turn the plugin off */
|
|
|
f92ce9 |
- plugin_delete(ecc, returntext, 0 /* not locked */);
|
|
|
f92ce9 |
- } else if (plugin_started == 2){
|
|
|
f92ce9 |
- /*
|
|
|
f92ce9 |
- * This probably can't happen, but...
|
|
|
f92ce9 |
- * the op failed, turn the plugin back on.
|
|
|
f92ce9 |
- */
|
|
|
f92ce9 |
- plugin_add(ecc, returntext, 0 /* not locked */);
|
|
|
f92ce9 |
+ if(!internal_op){
|
|
|
f92ce9 |
+ if(returncode == LDAP_SUCCESS){
|
|
|
f92ce9 |
+ dse_post_modify_plugin(ec, ecc, mods);
|
|
|
f92ce9 |
+ } else if(plugin_started){
|
|
|
f92ce9 |
+ if(plugin_started == 1){
|
|
|
f92ce9 |
+ /* the op failed, turn the plugin off */
|
|
|
f92ce9 |
+ plugin_delete(ecc, returntext, 0 /* not locked */);
|
|
|
f92ce9 |
+ } else if (plugin_started == 2){
|
|
|
f92ce9 |
+ /*
|
|
|
f92ce9 |
+ * This probably can't happen, but...
|
|
|
f92ce9 |
+ * the op failed, turn the plugin back on.
|
|
|
f92ce9 |
+ */
|
|
|
f92ce9 |
+ plugin_add(ecc, returntext, 0 /* not locked */);
|
|
|
f92ce9 |
+ }
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
|
|
|
f92ce9 |
@@ -2065,6 +2070,7 @@ static void
|
|
|
f92ce9 |
dse_post_modify_plugin(Slapi_Entry *entryBefore, Slapi_Entry *entryAfter, LDAPMod **mods)
|
|
|
f92ce9 |
{
|
|
|
f92ce9 |
char *enabled = NULL;
|
|
|
f92ce9 |
+ int restart_plugin = 1;
|
|
|
f92ce9 |
int i;
|
|
|
f92ce9 |
|
|
|
f92ce9 |
if (!slapi_entry_attr_hasvalue(entryBefore, SLAPI_ATTR_OBJECTCLASS, "nsSlapdPlugin") ||
|
|
|
f92ce9 |
@@ -2080,31 +2086,18 @@ dse_post_modify_plugin(Slapi_Entry *entryBefore, Slapi_Entry *entryAfter, LDAPMo
|
|
|
f92ce9 |
!strcasecmp(enabled, "on"))
|
|
|
f92ce9 |
{
|
|
|
f92ce9 |
for(i = 0; mods && mods[i]; i++){
|
|
|
f92ce9 |
- /* Check if we are modifying a plugin's config, if so restart the plugin */
|
|
|
f92ce9 |
- if (strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_PATH) == 0 ||
|
|
|
f92ce9 |
- strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_INITFN) == 0 ||
|
|
|
f92ce9 |
- strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_TYPE) == 0 ||
|
|
|
f92ce9 |
- strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_DEPENDS_ON_TYPE) == 0 ||
|
|
|
f92ce9 |
- strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_DEPENDS_ON_NAMED) == 0 ||
|
|
|
f92ce9 |
- strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_SCHEMA_CHECK) == 0 ||
|
|
|
f92ce9 |
- strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_BE_TXN) == 0 ||
|
|
|
f92ce9 |
- strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_TARGET_SUBTREE) == 0 ||
|
|
|
f92ce9 |
- strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_EXCLUDE_TARGET_SUBTREE) == 0 ||
|
|
|
f92ce9 |
- strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_BIND_SUBTREE) == 0 ||
|
|
|
f92ce9 |
- strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_EXCLUDE_BIND_SUBTREE) == 0 ||
|
|
|
f92ce9 |
- strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_LOAD_NOW) == 0 ||
|
|
|
f92ce9 |
- strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_LOAD_GLOBAL) == 0 ||
|
|
|
f92ce9 |
- strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_PRECEDENCE) == 0 ||
|
|
|
f92ce9 |
- strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_LOG_ACCESS) == 0 ||
|
|
|
f92ce9 |
- strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_LOG_AUDIT) == 0 )
|
|
|
f92ce9 |
- {
|
|
|
f92ce9 |
- /* for all other plugin config changes, restart the plugin */
|
|
|
f92ce9 |
- if(plugin_restart(entryBefore, entryAfter) != LDAP_SUCCESS){
|
|
|
f92ce9 |
- slapi_log_error(SLAPI_LOG_FATAL,"dse_post_modify_plugin", "The configuration change "
|
|
|
f92ce9 |
- "for plugin (%s) could not be applied dynamically, and will be ignored until "
|
|
|
f92ce9 |
- "the server is restarted.\n",
|
|
|
f92ce9 |
- slapi_entry_get_dn(entryBefore));
|
|
|
f92ce9 |
- }
|
|
|
f92ce9 |
+ if (strcasecmp(mods[i]->mod_type, ATTR_PLUGIN_ENABLED) == 0){
|
|
|
f92ce9 |
+ /* we already stop/started the pugin - don't do it again */
|
|
|
f92ce9 |
+ restart_plugin = 0;
|
|
|
f92ce9 |
+ break;
|
|
|
f92ce9 |
+ }
|
|
|
f92ce9 |
+ }
|
|
|
f92ce9 |
+ if(restart_plugin){ /* for all other plugin config changes, restart the plugin */
|
|
|
f92ce9 |
+ if(plugin_restart(entryBefore, entryAfter) != LDAP_SUCCESS){
|
|
|
f92ce9 |
+ slapi_log_error(SLAPI_LOG_FATAL,"dse_post_modify_plugin", "The configuration change "
|
|
|
f92ce9 |
+ "for plugin (%s) could not be applied dynamically, and will be ignored until "
|
|
|
f92ce9 |
+ "the server is restarted.\n",
|
|
|
f92ce9 |
+ slapi_entry_get_dn(entryBefore));
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
@@ -2690,7 +2683,10 @@ slapi_config_register_callback_plugin(int operation,
|
|
|
f92ce9 |
Slapi_DN dn;
|
|
|
f92ce9 |
|
|
|
f92ce9 |
slapi_sdn_init_dn_byref(&dn,base);
|
|
|
f92ce9 |
- rc = (NULL != dse_register_callback(pdse, operation, flags, &dn, scope, filter, fn, fn_arg, pb ? pb->pb_plugin: NULL));
|
|
|
f92ce9 |
+ /* if a pblock was passed, this is a plugin, so set the f_arg as the plugin */
|
|
|
f92ce9 |
+ rc = (NULL != dse_register_callback(pdse, operation, flags, &dn, scope, filter, fn,
|
|
|
f92ce9 |
+ pb ? (void*)pb->pb_plugin : fn_arg,
|
|
|
f92ce9 |
+ pb ? pb->pb_plugin: NULL));
|
|
|
f92ce9 |
slapi_sdn_done(&dn;;
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c
|
|
|
f92ce9 |
index dde3ce5..820c25f 100644
|
|
|
f92ce9 |
--- a/ldap/servers/slapd/plugin.c
|
|
|
f92ce9 |
+++ b/ldap/servers/slapd/plugin.c
|
|
|
f92ce9 |
@@ -58,6 +58,11 @@
|
|
|
f92ce9 |
#define CHECK_ALL 0
|
|
|
f92ce9 |
#define CHECK_TYPE 1
|
|
|
f92ce9 |
|
|
|
f92ce9 |
+/* plugin removal flags */
|
|
|
f92ce9 |
+#define PLUGIN_NOT_FOUND 0
|
|
|
f92ce9 |
+#define PLUGIN_REMOVED 1
|
|
|
f92ce9 |
+#define PLUGIN_BUSY 2
|
|
|
f92ce9 |
+
|
|
|
f92ce9 |
static char *critical_plugins[] = { "cn=ldbm database,cn=plugins,cn=config",
|
|
|
f92ce9 |
"cn=ACL Plugin,cn=plugins,cn=config",
|
|
|
f92ce9 |
"cn=ACL preoperation,cn=plugins,cn=config",
|
|
|
f92ce9 |
@@ -3294,7 +3299,7 @@ plugin_remove_plugins(struct slapdplugin *plugin_entry, char *plugin_type)
|
|
|
f92ce9 |
struct slapdplugin *plugin = NULL;
|
|
|
f92ce9 |
struct slapdplugin *plugin_next = NULL;
|
|
|
f92ce9 |
struct slapdplugin *plugin_prev = NULL;
|
|
|
f92ce9 |
- int removed = 0;
|
|
|
f92ce9 |
+ int removed = PLUGIN_NOT_FOUND;
|
|
|
f92ce9 |
int type;
|
|
|
f92ce9 |
|
|
|
f92ce9 |
/* look everywhere for other plugin functions with the plugin id */
|
|
|
f92ce9 |
@@ -3315,7 +3320,13 @@ plugin_remove_plugins(struct slapdplugin *plugin_entry, char *plugin_type)
|
|
|
f92ce9 |
|
|
|
f92ce9 |
pblock_init(&pb;;
|
|
|
f92ce9 |
plugin_set_stopped(plugin);
|
|
|
f92ce9 |
- plugin_op_all_finished(plugin);
|
|
|
f92ce9 |
+ if (slapi_counter_get_value(plugin->plg_op_counter) > 0){
|
|
|
f92ce9 |
+ /*
|
|
|
f92ce9 |
+ * Plugin is still busy, and we might be blocking it
|
|
|
f92ce9 |
+ * by holding global plugin lock so return for now.
|
|
|
f92ce9 |
+ */
|
|
|
f92ce9 |
+ return PLUGIN_BUSY;
|
|
|
f92ce9 |
+ }
|
|
|
f92ce9 |
plugin_call_one( plugin, SLAPI_PLUGIN_CLOSE_FN, &pb;;
|
|
|
f92ce9 |
|
|
|
f92ce9 |
if(plugin_prev){
|
|
|
f92ce9 |
@@ -3332,7 +3343,7 @@ plugin_remove_plugins(struct slapdplugin *plugin_entry, char *plugin_type)
|
|
|
f92ce9 |
plugin_remove_from_shutdown(plugin);
|
|
|
f92ce9 |
plugin->plg_removed = 1;
|
|
|
f92ce9 |
plugin->plg_started = 0;
|
|
|
f92ce9 |
- removed = 1;
|
|
|
f92ce9 |
+ removed = PLUGIN_REMOVED;
|
|
|
f92ce9 |
} else {
|
|
|
f92ce9 |
plugin_prev = plugin;
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
@@ -3362,15 +3373,10 @@ plugin_delete(Slapi_Entry *plugin_entry, char *returntext, int locked)
|
|
|
f92ce9 |
const char *plugin_dn = slapi_entry_get_dn_const(plugin_entry);
|
|
|
f92ce9 |
char *value = NULL;
|
|
|
f92ce9 |
int td_locked = 1;
|
|
|
f92ce9 |
- int removed = 0;
|
|
|
f92ce9 |
+ int removed = PLUGIN_BUSY;
|
|
|
f92ce9 |
int type = 0;
|
|
|
f92ce9 |
int rc = LDAP_SUCCESS;
|
|
|
f92ce9 |
|
|
|
f92ce9 |
- if(!locked){
|
|
|
f92ce9 |
- slapi_rwlock_wrlock(global_rwlock);
|
|
|
f92ce9 |
- }
|
|
|
f92ce9 |
- slapi_td_set_plugin_locked(&td_locked);
|
|
|
f92ce9 |
-
|
|
|
f92ce9 |
/* Critical server plugins can not be disabled */
|
|
|
f92ce9 |
if(plugin_is_critical(plugin_entry)){
|
|
|
f92ce9 |
LDAPDebug(LDAP_DEBUG_ANY, "plugin_delete: plugin \"%s\" is critical to server operations, and can not be disabled\n",
|
|
|
f92ce9 |
@@ -3390,54 +3396,62 @@ plugin_delete(Slapi_Entry *plugin_entry, char *returntext, int locked)
|
|
|
f92ce9 |
rc = -1;
|
|
|
f92ce9 |
goto done;
|
|
|
f92ce9 |
} else {
|
|
|
f92ce9 |
- rc = plugin_get_type_and_list(value, &type, &plugin_list);
|
|
|
f92ce9 |
- if ( rc != 0 ) {
|
|
|
f92ce9 |
- /* error: unknown plugin type */
|
|
|
f92ce9 |
- LDAPDebug(LDAP_DEBUG_ANY, "plugin_delete: unknown plugin type \"%s\" in entry \"%s\"\n",
|
|
|
f92ce9 |
- value, slapi_entry_get_dn_const(plugin_entry), 0);
|
|
|
f92ce9 |
- PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Plugin delete failed: unknown plugin type "
|
|
|
f92ce9 |
+ while(removed == PLUGIN_BUSY){
|
|
|
f92ce9 |
+ removed = PLUGIN_NOT_FOUND;
|
|
|
f92ce9 |
+ if(!locked){
|
|
|
f92ce9 |
+ slapi_rwlock_wrlock(global_rwlock);
|
|
|
f92ce9 |
+ }
|
|
|
f92ce9 |
+ slapi_td_set_plugin_locked(&td_locked);
|
|
|
f92ce9 |
+
|
|
|
f92ce9 |
+ rc = plugin_get_type_and_list(value, &type, &plugin_list);
|
|
|
f92ce9 |
+ if ( rc != 0 ) {
|
|
|
f92ce9 |
+ /* error: unknown plugin type */
|
|
|
f92ce9 |
+ LDAPDebug(LDAP_DEBUG_ANY, "plugin_delete: unknown plugin type \"%s\" in entry \"%s\"\n",
|
|
|
f92ce9 |
+ value, slapi_entry_get_dn_const(plugin_entry), 0);
|
|
|
f92ce9 |
+ PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Plugin delete failed: unknown plugin type "
|
|
|
f92ce9 |
"\"%s\" in entry.",value);
|
|
|
f92ce9 |
- rc = -1;
|
|
|
f92ce9 |
- goto done;
|
|
|
f92ce9 |
- }
|
|
|
f92ce9 |
+ rc = -1;
|
|
|
f92ce9 |
+ goto unlock;
|
|
|
f92ce9 |
+ }
|
|
|
f92ce9 |
|
|
|
f92ce9 |
- /*
|
|
|
f92ce9 |
- * Skip syntax/matching rule/database plugins - these can not be disabled as it
|
|
|
f92ce9 |
- * could break existing schema. We allow the update to occur, but it will
|
|
|
f92ce9 |
- * not take effect until the next server restart.
|
|
|
f92ce9 |
- */
|
|
|
f92ce9 |
- if(type == SLAPI_PLUGIN_SYNTAX || type == SLAPI_PLUGIN_MATCHINGRULE || type == SLAPI_PLUGIN_DATABASE){
|
|
|
f92ce9 |
- removed = 1; /* avoids error check below */
|
|
|
f92ce9 |
- goto done;
|
|
|
f92ce9 |
- }
|
|
|
f92ce9 |
+ /*
|
|
|
f92ce9 |
+ * Skip syntax/matching rule/database plugins - these can not be disabled as it
|
|
|
f92ce9 |
+ * could break existing schema. We allow the update to occur, but it will
|
|
|
f92ce9 |
+ * not take effect until the next server restart.
|
|
|
f92ce9 |
+ */
|
|
|
f92ce9 |
+ if(type == SLAPI_PLUGIN_SYNTAX || type == SLAPI_PLUGIN_MATCHINGRULE || type == SLAPI_PLUGIN_DATABASE){
|
|
|
f92ce9 |
+ removed = PLUGIN_REMOVED; /* avoids error check below */
|
|
|
f92ce9 |
+ goto unlock;
|
|
|
f92ce9 |
+ }
|
|
|
f92ce9 |
|
|
|
f92ce9 |
- /*
|
|
|
f92ce9 |
- * Now remove the plugin from the list and the hashtable
|
|
|
f92ce9 |
- */
|
|
|
f92ce9 |
- for(plugin = *plugin_list; plugin ; plugin = plugin->plg_next){
|
|
|
f92ce9 |
- if(strcasecmp(plugin->plg_dn, plugin_dn) == 0){
|
|
|
f92ce9 |
- /*
|
|
|
f92ce9 |
- * Make sure there are no other plugins that depend on this one before removing it
|
|
|
f92ce9 |
- */
|
|
|
f92ce9 |
- if(plugin_delete_check_dependency(plugin, CHECK_ALL, returntext) != LDAP_SUCCESS){
|
|
|
f92ce9 |
- LDAPDebug(LDAP_DEBUG_ANY, "plugin_delete: failed to disable/delete plugin (%s)\n",
|
|
|
f92ce9 |
- plugin->plg_dn,0,0);
|
|
|
f92ce9 |
- rc = -1;
|
|
|
f92ce9 |
- goto done;
|
|
|
f92ce9 |
+ /*
|
|
|
f92ce9 |
+ * Now remove the plugin from the list and the hashtable
|
|
|
f92ce9 |
+ */
|
|
|
f92ce9 |
+ for(plugin = *plugin_list; plugin ; plugin = plugin->plg_next){
|
|
|
f92ce9 |
+ if(strcasecmp(plugin->plg_dn, plugin_dn) == 0){
|
|
|
f92ce9 |
+ /*
|
|
|
f92ce9 |
+ * Make sure there are no other plugins that depend on this one before removing it
|
|
|
f92ce9 |
+ */
|
|
|
f92ce9 |
+ if(plugin_delete_check_dependency(plugin, CHECK_ALL, returntext) != LDAP_SUCCESS){
|
|
|
f92ce9 |
+ LDAPDebug(LDAP_DEBUG_ANY, "plugin_delete: failed to disable/delete plugin (%s)\n",
|
|
|
f92ce9 |
+ plugin->plg_dn,0,0);
|
|
|
f92ce9 |
+ rc = -1;
|
|
|
f92ce9 |
+ break;
|
|
|
f92ce9 |
+ }
|
|
|
f92ce9 |
+ removed = plugin_remove_plugins(plugin, value);
|
|
|
f92ce9 |
+ break;
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
- removed = plugin_remove_plugins(plugin, value);
|
|
|
f92ce9 |
- break;
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
+unlock:
|
|
|
f92ce9 |
+ if(!locked){
|
|
|
f92ce9 |
+ slapi_rwlock_unlock(global_rwlock);
|
|
|
f92ce9 |
+ }
|
|
|
f92ce9 |
+ td_locked = 0;
|
|
|
f92ce9 |
+ slapi_td_set_plugin_locked(&td_locked);
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
|
|
|
f92ce9 |
done:
|
|
|
f92ce9 |
- if(!locked){
|
|
|
f92ce9 |
- slapi_rwlock_unlock(global_rwlock);
|
|
|
f92ce9 |
- }
|
|
|
f92ce9 |
- td_locked = 0;
|
|
|
f92ce9 |
- slapi_td_set_plugin_locked(&td_locked);
|
|
|
f92ce9 |
-
|
|
|
f92ce9 |
slapi_ch_free_string(&value);
|
|
|
f92ce9 |
|
|
|
f92ce9 |
if(!removed && rc == 0){
|
|
|
f92ce9 |
diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c
|
|
|
f92ce9 |
index b1f7652..98ec88c 100644
|
|
|
f92ce9 |
--- a/ldap/servers/slapd/task.c
|
|
|
f92ce9 |
+++ b/ldap/servers/slapd/task.c
|
|
|
f92ce9 |
@@ -131,9 +131,9 @@ slapi_new_task(const char *dn)
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
|
|
|
f92ce9 |
Slapi_Task *
|
|
|
f92ce9 |
-slapi_plugin_new_task(const char *dn, void *plugin_pb)
|
|
|
f92ce9 |
+slapi_plugin_new_task(const char *dn, void *plugin)
|
|
|
f92ce9 |
{
|
|
|
f92ce9 |
- return new_task(dn, plugin_pb);
|
|
|
f92ce9 |
+ return new_task(dn, plugin);
|
|
|
f92ce9 |
}
|
|
|
f92ce9 |
|
|
|
f92ce9 |
/* slapi_destroy_task: destroy a task
|
|
|
f92ce9 |
@@ -540,7 +540,7 @@ slapi_plugin_task_register_handler(const char *name, dseCallbackFn func, Slapi_P
|
|
|
f92ce9 |
|
|
|
f92ce9 |
/* register add callback */
|
|
|
f92ce9 |
slapi_config_register_callback_plugin(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP,
|
|
|
f92ce9 |
- dn, LDAP_SCOPE_SUBTREE, "(objectclass=*)", func, NULL, plugin_pb);
|
|
|
f92ce9 |
+ dn, LDAP_SCOPE_SUBTREE, "(objectclass=*)", func, plugin_pb, plugin_pb);
|
|
|
f92ce9 |
/* deny modify/delete of the root task entry */
|
|
|
f92ce9 |
slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP,
|
|
|
f92ce9 |
dn, LDAP_SCOPE_BASE, "(objectclass=*)", task_deny, NULL);
|
|
|
f92ce9 |
@@ -583,11 +583,9 @@ void slapi_task_set_cancel_fn(Slapi_Task *task, TaskCallbackFn func)
|
|
|
f92ce9 |
***********************************/
|
|
|
f92ce9 |
/* create a new task, fill in DN, and setup modify callback */
|
|
|
f92ce9 |
static Slapi_Task *
|
|
|
f92ce9 |
-new_task(const char *rawdn, void *plugin_pb)
|
|
|
f92ce9 |
+new_task(const char *rawdn, void *plugin)
|
|
|
f92ce9 |
{
|
|
|
f92ce9 |
Slapi_Task *task = NULL;
|
|
|
f92ce9 |
- Slapi_PBlock *pb = (Slapi_PBlock *)plugin_pb;
|
|
|
f92ce9 |
- void *plugin = pb ? pb->pb_plugin : NULL;
|
|
|
f92ce9 |
char *dn = NULL;
|
|
|
f92ce9 |
|
|
|
f92ce9 |
if (rawdn == NULL) {
|
|
|
f92ce9 |
--
|
|
|
f92ce9 |
1.9.3
|
|
|
f92ce9 |
|