summaryrefslogtreecommitdiffstats
path: root/ldap/servers/slapd/backend_manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/servers/slapd/backend_manager.c')
-rw-r--r--ldap/servers/slapd/backend_manager.c770
1 files changed, 770 insertions, 0 deletions
diff --git a/ldap/servers/slapd/backend_manager.c b/ldap/servers/slapd/backend_manager.c
new file mode 100644
index 00000000..18a9e8a6
--- /dev/null
+++ b/ldap/servers/slapd/backend_manager.c
@@ -0,0 +1,770 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* backend_manager.c - routines for dealing with back-end databases */
+
+#include "slap.h"
+
+#define BACKEND_GRAB_SIZE 10
+
+/* JCM - searching the backend array is linear... */
+
+static int defsize = SLAPD_DEFAULT_SIZELIMIT;
+static int deftime = SLAPD_DEFAULT_TIMELIMIT;
+static int nbackends= 0;
+static Slapi_Backend **backends= NULL;
+static int maxbackends= 0;
+
+Slapi_Backend *
+slapi_be_new( const char *type, const char *name, int isprivate, int logchanges )
+{
+ Slapi_Backend *be;
+ int i;
+
+ /* should add some locking here to prevent concurrent access */
+ if ( nbackends == maxbackends )
+ {
+ int oldsize = maxbackends;
+ maxbackends += BACKEND_GRAB_SIZE;
+ backends = (Slapi_Backend **) slapi_ch_realloc( (char *) backends, maxbackends * sizeof(Slapi_Backend *) );
+ memset( &backends[oldsize], '\0', BACKEND_GRAB_SIZE * sizeof(Slapi_Backend *) );
+ }
+
+ for (i=0; ((i<maxbackends) && (backends[i])); i++)
+ ;
+
+ PR_ASSERT(i<maxbackends);
+
+ be = (Slapi_Backend *) slapi_ch_calloc(1, sizeof(Slapi_Backend));
+ be->be_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, name );
+ be_init( be, type, name, isprivate, logchanges, defsize, deftime );
+
+ backends[i] = be;
+ nbackends++;
+ return( be );
+}
+
+void
+slapi_be_stopping (Slapi_Backend *be)
+{
+ int i;
+
+ PR_Lock (be->be_state_lock);
+ for (i=0; ((i<maxbackends) && backends[i] != be); i++)
+ ;
+
+ PR_ASSERT(i<maxbackends);
+
+ backends[i] = NULL;
+ be->be_state = BE_STATE_DELETED;
+ if (be->be_lock != NULL)
+ {
+ PR_DestroyRWLock(be->be_lock);
+ be->be_lock = NULL;
+ }
+
+ nbackends--;
+ PR_Unlock (be->be_state_lock);
+}
+
+
+void
+slapi_be_free(Slapi_Backend **be)
+{
+ be_done(*be);
+ slapi_ch_free((void**)be);
+ *be = NULL;
+}
+
+static int
+be_plgfn_unwillingtoperform(Slapi_PBlock *pb)
+{
+ send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Operation on Directory Specific Entry not allowed", 0, NULL );
+ return -1;
+}
+
+/* JCM - Seems rather DSE specific... why's it here?... Should be in fedse.c... */
+
+Slapi_Backend *
+be_new_internal(struct dse *pdse, const char *type, const char *name)
+{
+ Slapi_Backend *be= slapi_be_new(type, name, 1 /* Private */, 0 /* Do Not Log Changes */);
+ be->be_database = (struct slapdplugin *) slapi_ch_calloc( 1, sizeof(struct slapdplugin) );
+ be->be_database->plg_private= (void*)pdse;
+ be->be_database->plg_bind= &dse_bind;
+ be->be_database->plg_unbind= &dse_unbind;
+ be->be_database->plg_search= &dse_search;
+ be->be_database->plg_next_search_entry= &dse_next_search_entry;
+ be->be_database->plg_compare= &be_plgfn_unwillingtoperform;
+ be->be_database->plg_modify= &dse_modify;
+ be->be_database->plg_modrdn= &be_plgfn_unwillingtoperform;
+ be->be_database->plg_add= &dse_add;
+ be->be_database->plg_delete= &dse_delete;
+ be->be_database->plg_abandon= &be_plgfn_unwillingtoperform;
+ be->be_database->plg_cleanup = dse_deletedse;
+ /* All the other function pointers default to NULL */
+ return be;
+}
+
+Slapi_Backend*
+slapi_get_first_backend (char **cookie)
+{
+ int i;
+
+ for (i = 0; i < maxbackends; i++)
+ {
+ if ( backends[i] && (backends[i]->be_state != BE_STATE_DELETED))
+ {
+ *cookie = (char*)slapi_ch_malloc (sizeof (int));
+ memcpy (*cookie, &i, sizeof (int));
+ return backends[i];
+ }
+ }
+
+ return NULL;
+}
+
+Slapi_Backend*
+slapi_get_next_backend (char *cookie)
+{
+ int i, last_be;
+ if (cookie == NULL)
+ {
+ LDAPDebug( LDAP_DEBUG_ARGS, "slapi_get_next_backend: NULL argument\n",
+ 0, 0, 0 );
+ return NULL;
+ }
+
+ last_be = *(int *)cookie;
+
+ if ( last_be < 0 || last_be >= maxbackends)
+ {
+ LDAPDebug( LDAP_DEBUG_ARGS, "slapi_get_next_backend: argument out of range\n",
+ 0, 0, 0 );
+ return NULL;
+ }
+
+ if (last_be == maxbackends - 1)
+ return NULL; /* done */
+
+ for (i = last_be + 1; i < maxbackends; i++)
+ {
+ if (backends[i] && (backends[i]->be_state != BE_STATE_DELETED))
+ {
+ memcpy (cookie, &i, sizeof (int));
+ return backends [i];
+ }
+ }
+
+ return NULL;
+}
+
+Slapi_Backend *
+g_get_user_backend( int n )
+{
+ int i, useri;
+
+ useri = 0;
+ for ( i = 0; i < maxbackends; i++ ) {
+ if ( (backends[i] == NULL) || (backends[i]->be_private == 1) ) {
+ continue;
+ }
+
+ if ( useri == n ) {
+ if (backends[i]->be_state != BE_STATE_DELETED)
+ return backends[i];
+ else
+ return NULL;
+ }
+ useri++;
+ }
+ return NULL;
+}
+
+void
+g_set_deftime(int val)
+{
+ deftime = val;
+}
+
+void
+g_set_defsize(int val)
+{
+ defsize = val;
+}
+
+int
+g_get_deftime()
+{
+ return deftime;
+}
+
+int
+g_get_defsize()
+{
+ return defsize;
+}
+
+int strtrimcasecmp(const char *s1, const char *s2)
+{
+ char * s1bis, *s2bis;
+ int len_s1 = 0, len_s2 = 0;
+
+ if ( ((s1 == NULL) && (s2 != NULL))
+ || ((s2 == NULL) && (s1 != NULL)) )
+ return 1;
+
+ if ((s1 == NULL) && (s2 == NULL))
+ return 0;
+
+ while (*s1 == ' ')
+ s1++;
+
+ while (*s2 == ' ')
+ s2++;
+
+ s1bis = (char *) s1;
+ while ((*s1bis != ' ') && (*s1bis != 0))
+ {
+ len_s1 ++;
+ s1bis ++;
+ }
+
+ s2bis = (char *) s2;
+ while ((*s2bis != ' ') && (*s2bis != 0))
+ {
+ len_s2 ++;
+ s2bis ++;
+ }
+
+ if (len_s2 != len_s1)
+ return 1;
+
+ return strncasecmp(s1, s2, len_s1);
+}
+/*
+ * Find the backend of the given type.
+ */
+Slapi_Backend *
+slapi_be_select_by_instance_name( const char *name )
+{
+ int i;
+ for ( i = 0; i < maxbackends; i++ )
+ {
+ if ( backends[i] && (backends[i]->be_state != BE_STATE_DELETED) &&
+ strtrimcasecmp( backends[i]->be_name, name ) == 0)
+ {
+ return backends[i];
+ }
+ }
+ return NULL;
+}
+
+/* void
+be_cleanupall()
+{
+ int i;
+ Slapi_PBlock pb;
+
+ for ( i = 0; i < maxbackends; i++ )
+ {
+ if ( backends[i] &&
+ backends[i]->be_cleanup != NULL &&
+ (backends[i]->be_state == BE_STATE_STOPPED ||
+ backends[i]->be_state == BE_STATE_DELETED))
+ {
+ slapi_pblock_set( &pb, SLAPI_PLUGIN, backends[i]->be_database );
+ slapi_pblock_set( &pb, SLAPI_BACKEND, backends[i] );
+
+ (*backends[i]->be_cleanup)( &pb );
+ }
+ }
+}*/
+
+void
+be_cleanupall()
+{
+ int i;
+ Slapi_PBlock pb;
+
+ for ( i = 0; i < maxbackends; i++ )
+ {
+ if (backends[i] &&
+ backends[i]->be_cleanup != NULL &&
+ (backends[i]->be_state == BE_STATE_STOPPED ||
+ backends[i]->be_state == BE_STATE_DELETED))
+ {
+ slapi_pblock_set( &pb, SLAPI_PLUGIN, backends[i]->be_database );
+ slapi_pblock_set( &pb, SLAPI_BACKEND, backends[i] );
+
+ (*backends[i]->be_cleanup)( &pb );
+ be_done(backends[i]);
+ slapi_ch_free((void **)&backends[i]);
+ }
+ }
+ slapi_ch_free((void**)&backends);
+}
+
+void
+be_flushall()
+{
+ int i;
+ Slapi_PBlock pb;
+
+ for ( i = 0; i < maxbackends; i++ )
+ {
+ if ( backends[i] &&
+ backends[i]->be_state == BE_STATE_STARTED &&
+ backends[i]->be_flush != NULL )
+ {
+ slapi_pblock_set( &pb, SLAPI_PLUGIN, backends[i]->be_database );
+ slapi_pblock_set( &pb, SLAPI_BACKEND, backends[i] );
+ (*backends[i]->be_flush)( &pb );
+ }
+ }
+}
+
+void
+be_unbindall(Connection *conn, Operation *op)
+{
+ int i;
+ Slapi_PBlock pb;
+
+ for ( i = 0; i < maxbackends; i++ )
+ {
+ if ( backends[i] && (backends[i]->be_unbind != NULL) )
+ {
+ pblock_init_common( &pb, backends[i], conn, op );
+
+ if ( plugin_call_plugins( &pb, SLAPI_PLUGIN_PRE_UNBIND_FN ) == 0 )
+ {
+ int rc;
+ slapi_pblock_set( &pb, SLAPI_PLUGIN, backends[i]->be_database );
+ if(backends[i]->be_state != BE_STATE_DELETED &&
+ backends[i]->be_unbind!=NULL)
+ {
+ rc = (*backends[i]->be_unbind)( &pb );
+ }
+ slapi_pblock_set( &pb, SLAPI_PLUGIN_OPRETURN, &rc );
+ (void) plugin_call_plugins( &pb, SLAPI_PLUGIN_POST_UNBIND_FN );
+ }
+ }
+ }
+}
+
+int
+be_nbackends_public()
+{
+ int i;
+ int n= 0;
+ for ( i = 0; i < maxbackends; i++ )
+ {
+ if ( backends[i] &&
+ (backends[i]->be_state != BE_STATE_DELETED) &&
+ (!backends[i]->be_private) )
+ {
+ n++;
+ }
+ }
+ return n;
+}
+
+/* backend instance management */
+/* JCM - These are hardcoded for the LDBM database */
+#define LDBM_CLASS_PREFIX "cn=ldbm database,cn=plugins,cn=config"
+#define LDBM_CONFIG_ENTRY "cn=config,cn=ldbm database,cn=plugins,cn=config"
+#define INSTANCE_ATTR "nsslapd-instance"
+#define SUFFIX_ATTR "nsslapd-suffix"
+#define CACHE_ATTR "nsslapd-cachememsize"
+
+/* add nsslapd-instance attribute to cn=config,cn=ldbm database,cn=plugins,cn=config
+ entry. This causes empty backend instance creation */
+/* JCM - Should be adding an instance entry, not an attr value */
+static int
+be_add_instance (const char *name, void *plugin_identity)
+{
+ Slapi_PBlock pb;
+ Slapi_Mods smods;
+ int rc;
+
+ PR_ASSERT (name && plugin_identity);
+
+ slapi_mods_init (&smods, 1);
+ slapi_mods_add(&smods, LDAP_MOD_ADD, INSTANCE_ATTR, strlen (name), name);
+
+ pblock_init (&pb);
+ slapi_modify_internal_set_pb (&pb, LDBM_CONFIG_ENTRY,
+ slapi_mods_get_ldapmods_byref(&smods), NULL,
+ NULL, plugin_identity, 0);
+ slapi_modify_internal_pb (&pb);
+ slapi_mods_done (&smods);
+
+ slapi_pblock_get (&pb, SLAPI_PLUGIN_INTOP_RESULT,&rc);
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: "
+ "failed to modify ldbm configuration entry; LDAP error - %d\n", rc);
+ pblock_done(&pb);
+ return -1;
+ }
+
+ pblock_done(&pb);
+ return 0;
+}
+
+static char*
+be_get_instance_dn (const char *index_name, const char *name)
+{
+ int len;
+ char *dn;
+
+ PR_ASSERT (name);
+
+ len = strlen ("cn=config,") + strlen (name) +
+ strlen (LDBM_CLASS_PREFIX) + 4; /* 4 = "cn=" + ',' + '\0' */
+
+ if (index_name)
+ {
+ len += strlen (index_name) + strlen ("cn=index,") + 4; /* 4 = "cn=" + ',' */
+ }
+
+ dn = (char*)slapi_ch_malloc (len);
+ if (dn)
+ {
+ if (index_name)
+ {
+ sprintf (dn, "cn=%s,cn=index,cn=config,cn=%s,%s", index_name, name,
+ LDBM_CLASS_PREFIX);
+ }
+ else
+ {
+ sprintf (dn, "cn=config,cn=%s,%s", name, LDBM_CLASS_PREFIX);
+ }
+ }
+
+ return dn;
+}
+
+
+/* configure newly added backend by modifying instance's configuration entry:
+ cn=config,cn=<instance name>,cn=ldbm database,cn=plugins,cn=config.
+ Can configure backend root and cache size */
+static int
+be_configure_instance (const char *name, const char *root, int cache_size,
+ void *plugin_identity)
+{
+ Slapi_PBlock pb;
+ Slapi_Mods smods;
+ char value [128];
+ char *dn;
+ int rc;
+
+ PR_ASSERT (name && root && plugin_identity);
+
+ dn = be_get_instance_dn (NULL, name);
+
+ slapi_mods_init (&smods, 2);
+ slapi_mods_add(&smods, LDAP_MOD_ADD, SUFFIX_ATTR, strlen (root), root);
+ if (cache_size > 0)
+ {
+ sprintf (value, "%d", cache_size);
+ slapi_mods_add(&smods, LDAP_MOD_REPLACE, CACHE_ATTR, strlen (value), value);
+ }
+
+ pblock_init (&pb);
+ slapi_modify_internal_set_pb (&pb, dn, slapi_mods_get_ldapmods_byref(&smods),
+ NULL, NULL, plugin_identity, 0);
+ slapi_modify_internal_pb (&pb);
+
+ slapi_mods_done (&smods);
+ slapi_ch_free ((void**)&dn);
+
+ slapi_pblock_get (&pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: "
+ "failed to update instance entry; LDAP error - %d\n", rc);
+ pblock_done(&pb);
+ return -1;
+ }
+
+ pblock_done(&pb);
+ return 0;
+}
+
+/* configure instance indexes by adding an index entry:
+ "cn=<attr name>,cn=index,cn=config,cn=<instance name>,
+ cn=ldbm database,cn=plugins,cn=config".*/
+static int
+be_configure_instance_indexes (const char *name, IndexConfig *indexes,
+ int index_count, void *plugin_identity)
+{
+ int rc;
+ Slapi_PBlock pb;
+ Slapi_Entry *e;
+ char *dn;
+ int i;
+ char *start, *end;
+ char index_type [16];
+
+ PR_ASSERT (name && indexes && index_count > 0 && plugin_identity);
+
+ for (i = 0; i < index_count; i++)
+ {
+ dn = be_get_instance_dn (indexes[i].attr_name, name);
+ e = slapi_entry_alloc ();
+ slapi_entry_init (e, dn, NULL);
+
+ /* add objectclases */
+ slapi_entry_add_string (e, "objectclass", "top");
+ slapi_entry_add_string (e, "objectclass", "nsIndex");
+ slapi_entry_add_string (e, "cn", indexes[i].attr_name);
+ slapi_entry_add_string (e, "nssystemindex", indexes[i].system ? "true" : "false");
+
+ start = indexes[i].index_type;
+ while ((end = strchr (start, ' ')) != NULL)
+ {
+ if ((end - start) >= 16)
+ continue;
+
+ strncpy (index_type, start, end - start);
+ slapi_entry_add_string (e, "nsindextype", index_type);
+ start = end + 1;
+ }
+
+ slapi_entry_add_string (e, "nsindextype", start);
+
+ pblock_init (&pb);
+ slapi_add_entry_internal_set_pb (&pb, e, NULL /* controls */, plugin_identity,
+ 0/* operation flags */);
+ slapi_add_internal_pb (&pb);
+
+ slapi_pblock_get (&pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: "
+ "failed to update instance entry; LDAP error - %d\n", rc);
+ pblock_done(&pb);
+ return -1;
+ }
+ }
+
+ pblock_done(&pb);
+ return 0;
+}
+
+int
+be_create_instance (const char *type, const char *name, const char *root,
+ int cache_size, IndexConfig *indexes, int index_count,
+ void *plugin_identity)
+{
+ int rc;
+
+ if (type == NULL || strcasecmp (type, "ldbm") != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: "
+ "invalid backend type: %s.\n", type ? type : "null");
+ return -1;
+ }
+
+ if (name == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: null instance name.\n");
+ return -1;
+ }
+
+ if (root == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: null root dn.\n");
+ return -1;
+ }
+
+ if (plugin_identity == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: null plugin identity.\n");
+ return -1;
+ }
+
+ rc = be_add_instance (name, plugin_identity);
+ if (rc != 0)
+ return rc;
+
+ rc = be_configure_instance (name, root, cache_size, plugin_identity);
+ if (rc != 0)
+ return rc;
+
+ if (index_count > 0)
+ rc = be_configure_instance_indexes (name, indexes, index_count, plugin_identity);
+
+ return rc;
+}
+
+int
+be_remove_instance (const char *type, const char *name, void *plugin_identity)
+{
+ int rc;
+ char *dn;
+ Slapi_PBlock pb;
+
+ if (type == NULL || strcasecmp (type, "ldbm") != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_remove_instance: "
+ "invalid backend type: %s.\n", type ? type : "null");
+ return -1;
+ }
+
+ if (name == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_remove_instance: null instance name.\n");
+ return -1;
+ }
+
+ if (plugin_identity == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_remove_instance: null plugin identity.\n");
+ return -1;
+ }
+
+ dn = be_get_instance_dn (NULL, name);
+
+ pblock_init (&pb);
+ slapi_delete_internal_set_pb (&pb, dn, NULL, NULL, plugin_identity, 0);
+ slapi_delete_internal_pb (&pb);
+
+ slapi_ch_free ((void**)&dn);
+
+ slapi_pblock_get (&pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: "
+ "failed to update instance entry; LDAP error - %d\n", rc);
+ pblock_done(&pb);
+ return -1;
+ }
+
+ pblock_done(&pb);
+ return 0;
+}
+
+void
+slapi_be_Rlock(Slapi_Backend * be)
+{
+ PR_RWLock_Rlock(be->be_lock);
+}
+
+void
+slapi_be_Wlock(Slapi_Backend * be)
+{
+ PR_RWLock_Wlock(be->be_lock);
+}
+
+void
+slapi_be_Unlock(Slapi_Backend * be)
+{
+ PR_RWLock_Unlock(be->be_lock);
+}
+
+/*
+ * lookup instance names by suffix.
+ * if isexact == 0: returns instances including ones that associates with
+ * its sub suffixes.
+ * e.g., suffix: "o=<suffix>" is given, these are returned:
+ * suffixes: o=<suffix>, ou=<ou>,o=<suffix>, ...
+ * instances: inst of "o=<suffix>",
+ * inst of "ou=<ou>,o=<suffix>",
+ * ...
+ * if isexact != 0: returns an instance that associates with the given suffix
+ * e.g., suffix: "o=<suffix>" is given, these are returned:
+ * suffixes: "o=<suffix>"
+ * instances: inst of "o=<suffix>"
+ * Note: if suffixes
+ */
+int
+slapi_lookup_instance_name_by_suffix(char *suffix,
+ char ***suffixes, char ***instances, int isexact)
+{
+ Slapi_Backend *be = NULL;
+ char *cookie = NULL;
+ const char *thisdn;
+ int thisdnlen;
+ int suffixlen;
+ int maxinst = 1;
+ int i;
+ int rval = -1;
+
+ if (instances == NULL)
+ return rval;
+
+ rval = 0;
+ suffixlen = strlen(suffix);
+ cookie = NULL;
+ be = slapi_get_first_backend (&cookie);
+ while (be) {
+ if (NULL == be->be_suffix) {
+ be = (backend *)slapi_get_next_backend (cookie);
+ continue;
+ }
+ PR_Lock(be->be_suffixlock);
+ for (i = 0; be->be_suffix && i < be->be_suffixcount; i++) {
+ thisdn = slapi_sdn_get_ndn(be->be_suffix[i]);
+ thisdnlen = slapi_sdn_get_ndn_len(be->be_suffix[i]);
+ if (isexact?suffixlen!=thisdnlen:suffixlen>thisdnlen)
+ continue;
+ if (isexact?(!slapi_UTF8CASECMP(suffix, (char *)thisdn)):
+ (!slapi_UTF8CASECMP(suffix,
+ (char *)thisdn+thisdnlen-suffixlen))) {
+ charray_add(instances, slapi_ch_strdup(be->be_name));
+ if (suffixes)
+ charray_add(suffixes, slapi_ch_strdup(thisdn));
+ }
+ }
+ PR_Unlock(be->be_suffixlock);
+ be = (backend *)slapi_get_next_backend (cookie);
+ }
+
+ return rval;
+}
+
+/*
+ * lookup instance names by included suffixes and excluded suffixes.
+ *
+ * Get instance names associated with the given included suffixes
+ * as well as the excluded suffixes.
+ * Subtract the excluded instances from the included instance.
+ * Assign the result to instances.
+ */
+int
+slapi_lookup_instance_name_by_suffixes(char **included, char **excluded,
+ char ***instances)
+{
+ char **incl_instances, **excl_instances;
+ char **p;
+ int rval = -1;
+
+ if (instances == NULL)
+ return rval;
+
+ *instances = NULL;
+ incl_instances = NULL;
+ for (p = included; p && *p; p++) {
+ if (slapi_lookup_instance_name_by_suffix(*p, NULL, &incl_instances, 0)
+ < 0)
+ return rval;
+ }
+
+ excl_instances = NULL;
+ for (p = excluded; p && *p; p++) {
+ /* okay to be empty */
+ slapi_lookup_instance_name_by_suffix(*p, NULL, &excl_instances, 0);
+ }
+
+ rval = 0;
+ if (excl_instances) {
+ charray_subtract(incl_instances, excl_instances, NULL);
+ charray_free(excl_instances);
+ }
+ *instances = incl_instances;
+ return rval;
+}