]> git.sur5r.net Git - openldap/commitdiff
Import dynamic debug level support from HEAD
authorHoward Chu <hyc@openldap.org>
Fri, 17 Feb 2006 08:38:40 +0000 (08:38 +0000)
committerHoward Chu <hyc@openldap.org>
Fri, 17 Feb 2006 08:38:40 +0000 (08:38 +0000)
servers/slapd/bconfig.c
servers/slapd/main.c
servers/slapd/overlays/pcache.c
servers/slapd/proto-slap.h
servers/slapd/slapcommon.c

index 0cc55ef101eedf39afc6c9f4abf2e9872060ec4b..926e5be839514822fbbb2002bb03fd7b6b2bbe52 100644 (file)
@@ -2076,7 +2076,7 @@ slap_loglevel_get( struct berval *s, int *l )
        rc = slap_verbmasks_append( &loglevel_ops, i, s, loglevel_ignore );
 
        if ( rc != 0 ) {
-               Debug( LDAP_DEBUG_ANY, "slap_loglevel_register(%lu, \"%s\") failed\n",
+               Debug( LDAP_DEBUG_ANY, "slap_loglevel_get(%lu, \"%s\") failed\n",
                        i, s->bv_val, 0 );
 
        } else {
index 82fec4b6b5d4d436c5c3a0c4c4feef088c5e4341..7c88dd93d0f04e976ef635a743039c6059926d75 100644 (file)
@@ -185,6 +185,71 @@ struct option_helper {
        { BER_BVNULL, 0, NULL, NULL }
 };
 
+int
+parse_debug_unknowns( char **unknowns, int *levelp )
+{
+       int i, level, rc = 0;
+
+       for ( i = 0; unknowns[ i ] != NULL; i++ ) {
+               level = 0;
+               if ( str2loglevel( unknowns[ i ], &level )) {
+                       fprintf( stderr,
+                               "unrecognized log level \"%s\"\n", unknowns[ i ] );
+                       rc = 1;
+               } else {
+                       *levelp |= level;
+               }
+       }
+       return rc;
+}
+
+int
+parse_debug_level( const char *arg, int *levelp, char ***unknowns )
+{
+       int     level;
+
+       if ( arg != NULL && arg[ 0 ] != '-' && !isdigit( arg[ 0 ] ) )
+       {
+               int     i;
+               char    **levels;
+
+               levels = ldap_str2charray( arg, "," );
+
+               for ( i = 0; levels[ i ] != NULL; i++ ) {
+                       level = 0;
+
+                       if ( str2loglevel( levels[ i ], &level ) ) {
+                               /* remember this for later */
+                               ldap_charray_add( unknowns, levels[ i ] );
+                               fprintf( stderr,
+                                       "unrecognized log level \"%s\" (deferred)\n",
+                                       levels[ i ] );
+                       } else {
+                               *levelp |= level;
+                       }
+               }
+
+               ldap_charray_free( levels );
+
+       } else {
+               if ( lutil_atoix( &level, arg, 0 ) != 0 ) {
+                       fprintf( stderr,
+                               "unrecognized log level "
+                               "\"%s\"\n", arg );
+                       return 1;
+               }
+
+               if ( level == 0 ) {
+                       *levelp = 0;
+
+               } else {
+                       *levelp |= level;
+               }
+       }
+
+       return 0;
+}
+
 static void
 usage( char *name )
 {
@@ -261,6 +326,9 @@ int main( int argc, char **argv )
        struct sync_cookie *scp = NULL;
        struct sync_cookie *scp_entry = NULL;
 
+       char **debug_unknowns = NULL;
+       char **syslog_unknowns = NULL;
+
        char *serverNamePrefix = "";
        size_t  l;
 
@@ -395,46 +463,13 @@ int main( int argc, char **argv )
                        int     level = 0;
 
                        no_detach = 1;
-#ifdef LDAP_DEBUG
-                       if ( optarg != NULL && optarg[ 0 ] != '-' && !isdigit( optarg[ 0 ] ) )
-                       {
-                               int     i, goterr = 0;
-                               char    **levels;
-
-                               levels = ldap_str2charray( optarg, "," );
-
-                               for ( i = 0; levels[ i ] != NULL; i++ ) {
-                                       level = 0;
-
-                                       if ( str2loglevel( levels[ i ], &level ) ) {
-                                               fprintf( stderr,
-                                                       "unrecognized log level "
-                                                       "\"%s\"\n", levels[ i ] );
-                                               goterr = 1;
-                                               /* but keep parsing... */
-
-                                       } else {
-                                               slap_debug |= level;
-                                       }
-                               }
-
-                               ldap_charray_free( levels );
-
-                               if ( goterr ) {
-                                       goto destroy;
-                               }
-
-                       } else {
-                               if ( lutil_atoix( &level, optarg, 0 ) != 0 ) {
-                                       fprintf( stderr,
-                                               "unrecognized log level "
-                                               "\"%s\"\n", optarg );
-                                       goto destroy;
-                               }
-                               slap_debug |= level;
+                       if ( parse_debug_level( optarg, &level, &debug_unknowns ) ) {
+                               goto destroy;
                        }
+#ifdef LDAP_DEBUG
+                       slap_debug |= level;
 #else
-                       if ( lutil_atoi( &level, optarg ) != 0 || level != 0 )
+                       if ( level != 0 )
                                fputs( "must compile with LDAP_DEBUG for debugging\n",
                                       stderr );
 #endif
@@ -483,8 +518,7 @@ int main( int argc, char **argv )
                }
 
                case 's':       /* set syslog level */
-                       if ( lutil_atoi( &ldap_syslog, optarg ) != 0 ) {
-                               fprintf( stderr, "unable to parse syslog level \"%s\"", optarg );
+                       if ( parse_debug_level( optarg, &ldap_syslog, &syslog_unknowns ) ) {
                                goto destroy;
                        }
                        break;
@@ -641,6 +675,21 @@ unhandled_option:;
                goto destroy;
        }
 
+       if ( debug_unknowns ) {
+               rc = parse_debug_unknowns( debug_unknowns, &slap_debug );
+               ldap_charray_free( debug_unknowns );
+               debug_unknowns = NULL;
+               if ( rc )
+                       goto destroy;
+       }
+       if ( syslog_unknowns ) {
+               rc = parse_debug_unknowns( syslog_unknowns, &ldap_syslog );
+               ldap_charray_free( syslog_unknowns );
+               syslog_unknowns = NULL;
+               if ( rc )
+                       goto destroy;
+       }
+
        if ( check & CHECK_CONFIG ) {
                fprintf( stderr, "config check succeeded\n" );
 
index d7f5eb5054ad0f2f7be5d62acc4cac773e8638d2..991c1ae25fa31afbdec2facf450064282a974c6b 100644 (file)
@@ -136,6 +136,8 @@ typedef struct cache_manager_s {
        query_manager*   qm;    /* query cache managed by the cache manager */
 } cache_manager;
 
+static int pcache_debug;
+
 static AttributeDescription *ad_queryid;
 static char *queryid_schema = "( 1.3.6.1.4.1.4203.666.1.12 NAME 'queryid' "
                        "DESC 'list of queries the entry belongs to' "
@@ -263,7 +265,7 @@ add_query_on_top (query_manager* qm, CachedQuery* qc)
 
        qc->lru_down = top;
        qc->lru_up = NULL;
-       Debug( LDAP_DEBUG_CACHE, "Base of added query = %s\n",
+       Debug( pcache_debug, "Base of added query = %s\n",
                        q->base.bv_val, 0, 0 );
 }
 
@@ -492,7 +494,7 @@ query_containment(Operation *op, query_manager *qm,
 
        MatchingRule* mrule = NULL;
        if (inputf != NULL) {
-               Debug( LDAP_DEBUG_CACHE, "Lock QC index = %d\n",
+               Debug( pcache_debug, "Lock QC index = %d\n",
                                template_index, 0, 0 );
                ldap_pvt_thread_rdwr_rlock(&(templa[template_index].t_rwlock));
                for(qc=templa[template_index].query; qc != NULL; qc= qc->next) {
@@ -523,7 +525,7 @@ query_containment(Operation *op, query_manager *qm,
                                                        &(fs->f_ava->aa_value), &text);
                                                if (rc != LDAP_SUCCESS) {
                                                        ldap_pvt_thread_rdwr_runlock(&(templa[template_index].t_rwlock));
-                                                       Debug( LDAP_DEBUG_CACHE,
+                                                       Debug( pcache_debug,
                                                        "Unlock: Exiting QC index=%d\n",
                                                        template_index, 0, 0 );
                                                        return NULL;
@@ -594,7 +596,7 @@ query_containment(Operation *op, query_manager *qm,
                                }
                        }
                }
-               Debug( LDAP_DEBUG_CACHE,
+               Debug( pcache_debug,
                        "Not answerable: Unlock QC index=%d\n",
                        template_index, 0, 0 );
                ldap_pvt_thread_rdwr_runlock(&(templa[template_index].t_rwlock));
@@ -636,7 +638,7 @@ static void add_query(
        }
        new_cached_query->lru_up = NULL;
        new_cached_query->lru_down = NULL;
-       Debug( LDAP_DEBUG_CACHE, "Added query expires at %ld\n",
+       Debug( pcache_debug, "Added query expires at %ld\n",
                        (long) new_cached_query->expiry_time, 0, 0 );
        new_query = (Query*)new_cached_query;
 
@@ -646,7 +648,7 @@ static void add_query(
        new_query->attrs = query->attrs;
 
        /* Adding a query    */
-       Debug( LDAP_DEBUG_CACHE, "Lock AQ index = %d\n",
+       Debug( pcache_debug, "Lock AQ index = %d\n",
                        template_index, 0, 0 );
        ldap_pvt_thread_rdwr_wlock(&templ->t_rwlock);
        if (templ->query == NULL)
@@ -657,10 +659,10 @@ static void add_query(
        new_cached_query->prev = NULL;
        templ->query = new_cached_query;
        templ->no_of_queries++;
-       Debug( LDAP_DEBUG_CACHE, "TEMPLATE %d QUERIES++ %d\n",
+       Debug( pcache_debug, "TEMPLATE %d QUERIES++ %d\n",
                        template_index, templ->no_of_queries, 0 );
 
-       Debug( LDAP_DEBUG_CACHE, "Unlock AQ index = %d \n",
+       Debug( pcache_debug, "Unlock AQ index = %d \n",
                        template_index, 0, 0 );
        ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);
 
@@ -702,7 +704,7 @@ static void cache_replacement(query_manager* qm, struct berval *result)
        result->bv_len = 0;
 
        if (!bottom) {
-               Debug ( LDAP_DEBUG_CACHE,
+               Debug ( pcache_debug,
                        "Cache replacement invoked without "
                        "any query in LRU list\n", 0, 0, 0 );
                ldap_pvt_thread_mutex_unlock(&qm->lru_mutex);
@@ -716,12 +718,12 @@ static void cache_replacement(query_manager* qm, struct berval *result)
        *result = bottom->q_uuid;
        bottom->q_uuid.bv_val = NULL;
 
-       Debug( LDAP_DEBUG_CACHE, "Lock CR index = %d\n", temp_id, 0, 0 );
+       Debug( pcache_debug, "Lock CR index = %d\n", temp_id, 0, 0 );
        ldap_pvt_thread_rdwr_wlock(&(qm->templates[temp_id].t_rwlock));
        remove_from_template(bottom, (qm->templates+temp_id));
-       Debug( LDAP_DEBUG_CACHE, "TEMPLATE %d QUERIES-- %d\n",
+       Debug( pcache_debug, "TEMPLATE %d QUERIES-- %d\n",
                temp_id, qm->templates[temp_id].no_of_queries, 0 );
-       Debug( LDAP_DEBUG_CACHE, "Unlock CR index = %d\n", temp_id, 0, 0 );
+       Debug( pcache_debug, "Unlock CR index = %d\n", temp_id, 0, 0 );
        ldap_pvt_thread_rdwr_wunlock(&(qm->templates[temp_id].t_rwlock));
        free_query(bottom);
 }
@@ -814,7 +816,7 @@ remove_query_data (
                op->o_req_ndn = qi->xdn;
 
                if ( qi->del) {
-                       Debug( LDAP_DEBUG_CACHE, "DELETING ENTRY TEMPLATE=%s\n",
+                       Debug( pcache_debug, "DELETING ENTRY TEMPLATE=%s\n",
                                query_uuid->bv_val, 0, 0 );
 
                        op->o_tag = LDAP_REQ_DELETE;
@@ -836,7 +838,7 @@ remove_query_data (
                        mod.sml_values = vals;
                        mod.sml_nvalues = NULL;
                        mod.sml_next = NULL;
-                       Debug( LDAP_DEBUG_CACHE,
+                       Debug( pcache_debug,
                                "REMOVING TEMP ATTR : TEMPLATE=%s\n",
                                query_uuid->bv_val, 0, 0 );
 
@@ -978,7 +980,7 @@ cache_entries(
        op_tmp.o_dn = cm->db.be_rootdn;
        op_tmp.o_ndn = cm->db.be_rootndn;
 
-       Debug( LDAP_DEBUG_CACHE, "UUID for query being added = %s\n",
+       Debug( pcache_debug, "UUID for query being added = %s\n",
                        uuidbuf, 0, 0 );
 
        for ( e=si->head; e; e=si->head ) {
@@ -987,23 +989,23 @@ cache_entries(
                while ( cm->cur_entries > (cm->max_entries) ) {
                                qm->crfunc(qm, &crp_uuid);
                                if (crp_uuid.bv_val) {
-                                       Debug( LDAP_DEBUG_CACHE,
+                                       Debug( pcache_debug,
                                                "Removing query UUID %s\n",
                                                crp_uuid.bv_val, 0, 0 );
                                        return_val = remove_query_data(&op_tmp, rs, &crp_uuid);
-                                       Debug( LDAP_DEBUG_CACHE,
+                                       Debug( pcache_debug,
                                                "QUERY REMOVED, SIZE=%d\n",
                                                return_val, 0, 0);
                                        ldap_pvt_thread_mutex_lock(
                                                        &cm->cache_mutex );
                                        cm->cur_entries -= return_val;
                                        cm->num_cached_queries--;
-                                       Debug( LDAP_DEBUG_CACHE,
+                                       Debug( pcache_debug,
                                                "STORED QUERIES = %lu\n",
                                                cm->num_cached_queries, 0, 0 );
                                        ldap_pvt_thread_mutex_unlock(
                                                        &cm->cache_mutex );
-                                       Debug( LDAP_DEBUG_CACHE,
+                                       Debug( pcache_debug,
                                                "QUERY REMOVED, CACHE ="
                                                "%d entries\n",
                                                cm->cur_entries, 0, 0 );
@@ -1013,7 +1015,7 @@ cache_entries(
                return_val = merge_entry(&op_tmp, e, query_uuid);
                ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
                cm->cur_entries += return_val;
-               Debug( LDAP_DEBUG_CACHE,
+               Debug( pcache_debug,
                        "ENTRY ADDED/MERGED, CACHED ENTRIES=%d\n",
                        cm->cur_entries, 0, 0 );
                return_val = 0;
@@ -1075,7 +1077,7 @@ pcache_response(
 
                        ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
                        cm->num_cached_queries++;
-                       Debug( LDAP_DEBUG_CACHE, "STORED QUERIES = %lu\n",
+                       Debug( pcache_debug, "STORED QUERIES = %lu\n",
                                        cm->num_cached_queries, 0, 0 );
                        ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
 
@@ -1178,7 +1180,7 @@ pcache_chk_controls(
                /* fallthru */
 
        case SLAP_CONTROL_CRITICAL:
-               Debug( LDAP_DEBUG_CACHE, "%s: "
+               Debug( pcache_debug, "%s: "
                        "%scritical pagedResults control "
                        "disabled with proxy cache%s.\n",
                        op->o_log_prefix, non, stripped );
@@ -1229,7 +1231,7 @@ pcache_op_search(
                return SLAP_CB_CONTINUE;
        }
 
-       Debug( LDAP_DEBUG_CACHE, "query template of incoming query = %s\n",
+       Debug( pcache_debug, "query template of incoming query = %s\n",
                                        tempstr.bv_val, 0, 0 );
 
        /* FIXME: cannot cache/answer requests with pagedResults control */
@@ -1274,7 +1276,7 @@ pcache_op_search(
                BackendDB       *save_bd = op->o_bd;
                slap_callback   *save_cb = op->o_callback;
 
-               Debug( LDAP_DEBUG_CACHE, "QUERY ANSWERABLE\n", 0, 0, 0 );
+               Debug( pcache_debug, "QUERY ANSWERABLE\n", 0, 0, 0 );
                op->o_tmpfree( filter_attrs, op->o_tmpmemctx );
                ldap_pvt_thread_rdwr_runlock(&qm->templates[i].t_rwlock);
                if ( BER_BVISNULL( &answerable->q_uuid )) {
@@ -1291,7 +1293,7 @@ pcache_op_search(
                return i;
        }
 
-       Debug( LDAP_DEBUG_CACHE, "QUERY NOT ANSWERABLE\n", 0, 0, 0 );
+       Debug( pcache_debug, "QUERY NOT ANSWERABLE\n", 0, 0, 0 );
 
        ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
        if (cm->num_cached_queries >= cm->max_queries) {
@@ -1306,7 +1308,7 @@ pcache_op_search(
                slap_callback           *cb;
                struct search_info      *si;
 
-               Debug( LDAP_DEBUG_CACHE, "QUERY CACHEABLE\n", 0, 0, 0 );
+               Debug( pcache_debug, "QUERY CACHEABLE\n", 0, 0, 0 );
                query.filter = filter_dup(op->ors_filter, NULL);
                add_filter_attrs(op, &query.attrs, &qm->attr_sets[attr_set],
                        filter_attrs, fattr_cnt, fattr_got_oc);
@@ -1343,7 +1345,7 @@ pcache_op_search(
                }
 
        } else {
-               Debug( LDAP_DEBUG_CACHE, "QUERY NOT CACHEABLE\n",
+               Debug( pcache_debug, "QUERY NOT CACHEABLE\n",
                                        0, 0, 0);
        }
 
@@ -1423,13 +1425,13 @@ consistency_check(
                if ( query ) pause = 0;
                op->o_time = slap_get_time();
                while (query && (query->expiry_time < op->o_time)) {
-                       Debug( LDAP_DEBUG_CACHE, "Lock CR index = %d\n",
+                       Debug( pcache_debug, "Lock CR index = %d\n",
                                        i, 0, 0 );
                        ldap_pvt_thread_rdwr_wlock(&templ->t_rwlock);
                        remove_from_template(query, templ);
-                       Debug( LDAP_DEBUG_CACHE, "TEMPLATE %d QUERIES-- %d\n",
+                       Debug( pcache_debug, "TEMPLATE %d QUERIES-- %d\n",
                                        i, templ->no_of_queries, 0 );
-                       Debug( LDAP_DEBUG_CACHE, "Unlock CR index = %d\n",
+                       Debug( pcache_debug, "Unlock CR index = %d\n",
                                        i, 0, 0 );
                        ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);
                        ldap_pvt_thread_mutex_lock(&qm->lru_mutex);
@@ -1439,15 +1441,15 @@ consistency_check(
                                return_val = 0;
                        else
                                return_val = remove_query_data(op, &rs, &query->q_uuid);
-                       Debug( LDAP_DEBUG_CACHE, "STALE QUERY REMOVED, SIZE=%d\n",
+                       Debug( pcache_debug, "STALE QUERY REMOVED, SIZE=%d\n",
                                                return_val, 0, 0 );
                        ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
                        cm->cur_entries -= return_val;
                        cm->num_cached_queries--;
-                       Debug( LDAP_DEBUG_CACHE, "STORED QUERIES = %lu\n",
+                       Debug( pcache_debug, "STORED QUERIES = %lu\n",
                                        cm->num_cached_queries, 0, 0 );
                        ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
-                       Debug( LDAP_DEBUG_CACHE,
+                       Debug( pcache_debug,
                                "STALE QUERY REMOVED, CACHE ="
                                "%d entries\n",
                                cm->cur_entries, 0, 0 );
@@ -1729,7 +1731,7 @@ pc_cf_gen( ConfigArgs *c )
                        return( 1 );
                }
                cm->cc_period = (time_t)t;
-               Debug( LDAP_DEBUG_CACHE,
+               Debug( pcache_debug,
                                "Total # of attribute sets to be cached = %d.\n",
                                cm->numattrsets, 0, 0 );
                qm->attr_sets = ( struct attr_set * )ch_calloc( cm->numattrsets,
@@ -1830,15 +1832,15 @@ pc_cf_gen( ConfigArgs *c )
                temp->no_of_queries = 0;
 
                ber_str2bv( c->argv[1], 0, 1, &temp->querystr );
-               Debug( LDAP_DEBUG_CACHE, "Template:\n", 0, 0, 0 );
-               Debug( LDAP_DEBUG_CACHE, "  query template: %s\n",
+               Debug( pcache_debug, "Template:\n", 0, 0, 0 );
+               Debug( pcache_debug, "  query template: %s\n",
                                temp->querystr.bv_val, 0, 0 );
                temp->attr_set_index = i;
                qm->attr_sets[i].flags |= PC_REFERENCED;
-               Debug( LDAP_DEBUG_CACHE, "  attributes: \n", 0, 0, 0 );
+               Debug( pcache_debug, "  attributes: \n", 0, 0, 0 );
                if ( ( attrarray = qm->attr_sets[i].attrs ) != NULL ) {
                        for ( i=0; attrarray[i].an_name.bv_val; i++ )
-                               Debug( LDAP_DEBUG_CACHE, "\t%s\n",
+                               Debug( pcache_debug, "\t%s\n",
                                        attrarray[i].an_name.bv_val, 0, 0 );
                }
                temp++; 
@@ -2078,6 +2080,10 @@ int pcache_initialize()
        LDAPAttributeType *at;
        int code;
        const char *err;
+       struct berval debugbv = BER_BVC("pcache");
+
+       if (( code = slap_loglevel_get( &debugbv, &pcache_debug )))
+               return code;
 
        at = ldap_str2attributetype( queryid_schema, &code, &err,
                LDAP_SCHEMA_ALLOW_ALL );
index 3d745ba80fe5b13b65a29d89321e921be85c3c9e..cb68939fbd7103342c8f0c41630b108456b0ca77 100644 (file)
@@ -1007,6 +1007,14 @@ LDAP_SLAPD_F (FILE *) lock_fopen LDAP_P(( const char *fname,
        const char *type, FILE **lfp ));
 LDAP_SLAPD_F (int) lock_fclose LDAP_P(( FILE *fp, FILE *lfp ));
 
+/*
+ * main.c
+ */
+LDAP_SLAPD_F (int)
+parse_debug_level LDAP_P(( const char *arg, int *levelp, char ***unknowns ));
+LDAP_SLAPD_F (int)
+parse_debug_unknowns LDAP_P(( char **unknowns, int *levelp ));
+
 /*
  * matchedValues.c
  */
index 581e06635284a9f291edc8e963c79def96876010..59e1e01cf359190006c5d6b693584f285daa120d 100644 (file)
@@ -174,6 +174,8 @@ parse_slapacl( void )
  *     argc, argv      command line arguments
  */
 
+static int need_shutdown;
+
 void
 slap_tool_init(
        const char* progname,
@@ -187,6 +189,7 @@ slap_tool_init(
        char *filterstr = NULL;
        char *subtree = NULL;
        char *ldiffile  = NULL;
+       char **debug_unknowns = NULL;
        int rc, i, dbnum;
        int mode = SLAP_TOOL_MODE;
        int truncatemode = 0;
@@ -195,7 +198,7 @@ slap_tool_init(
 #ifdef LDAP_DEBUG
        /* tools default to "none", so that at least LDAP_DEBUG_ANY 
         * messages show up; use -d 0 to reset */
-       ldap_debug = LDAP_DEBUG_NONE;
+       slap_debug = LDAP_DEBUG_NONE;
 #endif
 
 #ifdef CSRIMALLOC
@@ -265,53 +268,19 @@ slap_tool_init(
                case 'd': {     /* turn on debugging */
                        int     level = 0;
 
+                       if ( parse_debug_level( optarg, &level, &debug_unknowns ) ) {
+                               usage( tool, progname );
+                       }
 #ifdef LDAP_DEBUG
-                       if ( optarg != NULL && optarg[ 0 ] != '-' && !isdigit( optarg[ 0 ] ) )
-                       {
-                               int     i, goterr = 0;
-                               char    **levels;
-
-                               levels = ldap_str2charray( optarg, "," );
-
-                               for ( i = 0; levels[ i ] != NULL; i++ ) {
-                                       level = 0;
-
-                                       if ( str2loglevel( levels[ i ], &level ) ) {
-                                               fprintf( stderr,
-                                                       "unrecognized log level "
-                                                       "\"%s\"\n", levels[ i ] );
-                                               goterr = 1;
-                                               /* but keep parsing... */
-
-                                       } else {
-                                               if ( level != 0 ) {
-                                                       slap_debug |= level;
-
-                                               } else {
-                                                       /* allow to reset log level */
-                                                       slap_debug = 0;
-                                               }
-                                       }
-                               }
+                       if ( level == 0 ) {
+                               /* allow to reset log level */
+                               slap_debug = 0;
 
                        } else {
-                               if ( lutil_atoix( &level, optarg, 0 ) != 0 ) {
-                                       fprintf( stderr,
-                                               "unrecognized log level "
-                                               "\"%s\"\n", optarg );
-                                       exit( EXIT_FAILURE );
-                               }
-
-                               if ( level != 0 ) {
-                                       slap_debug |= level;
-
-                               } else {
-                                       /* allow to reset log level */
-                                       slap_debug = 0;
-                               }
+                               slap_debug |= level;
                        }
 #else
-                       if ( lutil_atoi( &level, optarg ) != 0 || level != 0 )
+                       if ( level != 0 )
                                fputs( "must compile with LDAP_DEBUG for debugging\n",
                                       stderr );
 #endif
@@ -486,6 +455,14 @@ slap_tool_init(
                exit( EXIT_FAILURE );
        }
 
+       if ( debug_unknowns ) {
+               rc = parse_debug_unknowns( debug_unknowns, &slap_debug );
+               ldap_charray_free( debug_unknowns );
+               debug_unknowns = NULL;
+               if ( rc )
+                       exit( EXIT_FAILURE );
+       }
+
        at_oc_cache = 1;
 
        switch ( tool ) {
@@ -659,27 +636,33 @@ startup:;
        }
 
        /* slapdn doesn't specify a backend to startup */
-       if ( !dryrun && tool != SLAPDN && slap_startup( be ) ) {
-               switch ( tool ) {
-               case SLAPTEST:
-                       fprintf( stderr, "slap_startup failed "
-                                       "(test would succeed using "
-                                       "the -u switch)\n" );
-                       break;
+       if ( !dryrun && tool != SLAPDN ) {
+               need_shutdown = 1;
+
+               if ( slap_startup( be ) ) {
+                       switch ( tool ) {
+                       case SLAPTEST:
+                               fprintf( stderr, "slap_startup failed "
+                                               "(test would succeed using "
+                                               "the -u switch)\n" );
+                               break;
+
+                       default:
+                               fprintf( stderr, "slap_startup failed\n" );
+                               break;
+                       }
 
-               default:
-                       fprintf( stderr, "slap_startup failed\n" );
-                       break;
+                       exit( EXIT_FAILURE );
                }
-               
-               exit( EXIT_FAILURE );
        }
 }
 
 void slap_tool_destroy( void )
 {
        if ( !dryrun ) {
-               slap_shutdown( be );
+               if ( need_shutdown ) {
+                       slap_shutdown( be );
+               }
                slap_destroy();
        }
 #ifdef SLAPD_MODULES