Back to index

openldap  2.4.31
monitor.c
Go to the documentation of this file.
00001 /* monitor.c - monitor mdb backend */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2000-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 
00017 #include "portable.h"
00018 
00019 #include <stdio.h>
00020 #include <ac/string.h>
00021 #include <ac/unistd.h>
00022 #include <ac/stdlib.h>
00023 #include <ac/errno.h>
00024 #include <sys/stat.h>
00025 #include "lutil.h"
00026 #include "back-mdb.h"
00027 
00028 #include "../back-monitor/back-monitor.h"
00029 
00030 #include "config.h"
00031 
00032 static ObjectClass          *oc_olmMDBDatabase;
00033 
00034 static AttributeDescription *ad_olmDbDirectory;
00035 
00036 #ifdef MDB_MONITOR_IDX
00037 static int
00038 mdb_monitor_idx_entry_add(
00039        struct mdb_info      *mdb,
00040        Entry         *e );
00041 
00042 static AttributeDescription *ad_olmDbNotIndexed;
00043 #endif /* MDB_MONITOR_IDX */
00044 
00045 /*
00046  * NOTE: there's some confusion in monitor OID arc;
00047  * by now, let's consider:
00048  * 
00049  * Subsystems monitor attributes   1.3.6.1.4.1.4203.666.1.55.0
00050  * Databases monitor attributes           1.3.6.1.4.1.4203.666.1.55.0.1
00051  * MDB database monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1.3
00052  *
00053  * Subsystems monitor objectclasses       1.3.6.1.4.1.4203.666.3.16.0
00054  * Databases monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1
00055  * MDB database monitor objectclasses     1.3.6.1.4.1.4203.666.3.16.0.1.3
00056  */
00057 
00058 static struct {
00059        char                 *name;
00060        char                 *oid;
00061 }             s_oid[] = {
00062        { "olmMDBAttributes",                     "olmDatabaseAttributes:1" },
00063        { "olmMDBObjectClasses",           "olmDatabaseObjectClasses:1" },
00064 
00065        { NULL }
00066 };
00067 
00068 static struct {
00069        char                 *desc;
00070        AttributeDescription **ad;
00071 }             s_at[] = {
00072        { "( olmDatabaseAttributes:1 "
00073               "NAME ( 'olmDbDirectory' ) "
00074               "DESC 'Path name of the directory "
00075                      "where the database environment resides' "
00076               "SUP monitoredInfo "
00077               "NO-USER-MODIFICATION "
00078               "USAGE dSAOperation )",
00079               &ad_olmDbDirectory },
00080 
00081 #ifdef MDB_MONITOR_IDX
00082        { "( olmDatabaseAttributes:2 "
00083               "NAME ( 'olmDbNotIndexed' ) "
00084               "DESC 'Missing indexes resulting from candidate selection' "
00085               "SUP monitoredInfo "
00086               "NO-USER-MODIFICATION "
00087               "USAGE dSAOperation )",
00088               &ad_olmDbNotIndexed },
00089 #endif /* MDB_MONITOR_IDX */
00090 
00091        { NULL }
00092 };
00093 
00094 static struct {
00095        char          *desc;
00096        ObjectClass   **oc;
00097 }             s_oc[] = {
00098        /* augments an existing object, so it must be AUXILIARY
00099         * FIXME: derive from some ABSTRACT "monitoredEntity"? */
00100        { "( olmMDBObjectClasses:2 "
00101               "NAME ( 'olmMDBDatabase' ) "
00102               "SUP top AUXILIARY "
00103               "MAY ( "
00104                      "olmDbDirectory "
00105 #ifdef MDB_MONITOR_IDX
00106                      "$ olmDbNotIndexed "
00107 #endif /* MDB_MONITOR_IDX */
00108                      ") )",
00109               &oc_olmMDBDatabase },
00110 
00111        { NULL }
00112 };
00113 
00114 static int
00115 mdb_monitor_update(
00116        Operation     *op,
00117        SlapReply     *rs,
00118        Entry         *e,
00119        void          *priv )
00120 {
00121        struct mdb_info             *mdb = (struct mdb_info *) priv;
00122 
00123 #ifdef MDB_MONITOR_IDX
00124        mdb_monitor_idx_entry_add( mdb, e );
00125 #endif /* MDB_MONITOR_IDX */
00126 
00127        return SLAP_CB_CONTINUE;
00128 }
00129 
00130 #if 0  /* uncomment if required */
00131 static int
00132 mdb_monitor_modify(
00133        Operation     *op,
00134        SlapReply     *rs,
00135        Entry         *e,
00136        void          *priv )
00137 {
00138        return SLAP_CB_CONTINUE;
00139 }
00140 #endif
00141 
00142 static int
00143 mdb_monitor_free(
00144        Entry         *e,
00145        void          **priv )
00146 {
00147        struct berval values[ 2 ];
00148        Modification  mod = { 0 };
00149 
00150        const char    *text;
00151        char          textbuf[ SLAP_TEXT_BUFLEN ];
00152 
00153        int           i, rc;
00154 
00155        /* NOTE: if slap_shutdown != 0, priv might have already been freed */
00156        *priv = NULL;
00157 
00158        /* Remove objectClass */
00159        mod.sm_op = LDAP_MOD_DELETE;
00160        mod.sm_desc = slap_schema.si_ad_objectClass;
00161        mod.sm_values = values;
00162        mod.sm_numvals = 1;
00163        values[ 0 ] = oc_olmMDBDatabase->soc_cname;
00164        BER_BVZERO( &values[ 1 ] );
00165 
00166        rc = modify_delete_values( e, &mod, 1, &text,
00167               textbuf, sizeof( textbuf ) );
00168        /* don't care too much about return code... */
00169 
00170        /* remove attrs */
00171        mod.sm_values = NULL;
00172        mod.sm_numvals = 0;
00173        for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
00174               mod.sm_desc = *s_at[ i ].ad;
00175               rc = modify_delete_values( e, &mod, 1, &text,
00176                      textbuf, sizeof( textbuf ) );
00177               /* don't care too much about return code... */
00178        }
00179        
00180        return SLAP_CB_CONTINUE;
00181 }
00182 
00183 /*
00184  * call from within mdb_initialize()
00185  */
00186 static int
00187 mdb_monitor_initialize( void )
00188 {
00189        int           i, code;
00190        ConfigArgs c;
00191        char   *argv[ 3 ];
00192 
00193        static int    mdb_monitor_initialized = 0;
00194 
00195        /* set to 0 when successfully initialized; otherwise, remember failure */
00196        static int    mdb_monitor_initialized_failure = 1;
00197 
00198        if ( mdb_monitor_initialized++ ) {
00199               return mdb_monitor_initialized_failure;
00200        }
00201 
00202        if ( backend_info( "monitor" ) == NULL ) {
00203               return -1;
00204        }
00205 
00206        /* register schema here */
00207 
00208        argv[ 0 ] = "back-mdb monitor";
00209        c.argv = argv;
00210        c.argc = 3;
00211        c.fname = argv[0];
00212 
00213        for ( i = 0; s_oid[ i ].name; i++ ) {
00214               c.lineno = i;
00215               argv[ 1 ] = s_oid[ i ].name;
00216               argv[ 2 ] = s_oid[ i ].oid;
00217 
00218               if ( parse_oidm( &c, 0, NULL ) != 0 ) {
00219                      Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
00220                             ": unable to add "
00221                             "objectIdentifier \"%s=%s\"\n",
00222                             s_oid[ i ].name, s_oid[ i ].oid, 0 );
00223                      return 2;
00224               }
00225        }
00226 
00227        for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
00228               code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 );
00229               if ( code != LDAP_SUCCESS ) {
00230                      Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
00231                             ": register_at failed for attributeType (%s)\n",
00232                             s_at[ i ].desc, 0, 0 );
00233                      return 3;
00234 
00235               } else {
00236                      (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
00237               }
00238        }
00239 
00240        for ( i = 0; s_oc[ i ].desc != NULL; i++ ) {
00241               code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 );
00242               if ( code != LDAP_SUCCESS ) {
00243                      Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
00244                             ": register_oc failed for objectClass (%s)\n",
00245                             s_oc[ i ].desc, 0, 0 );
00246                      return 4;
00247 
00248               } else {
00249                      (*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE;
00250               }
00251        }
00252 
00253        return ( mdb_monitor_initialized_failure = LDAP_SUCCESS );
00254 }
00255 
00256 /*
00257  * call from within mdb_db_init()
00258  */
00259 int
00260 mdb_monitor_db_init( BackendDB *be )
00261 {
00262        struct mdb_info             *mdb = (struct mdb_info *) be->be_private;
00263 
00264        if ( mdb_monitor_initialize() == LDAP_SUCCESS ) {
00265               /* monitoring in back-mdb is on by default */
00266               SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
00267        }
00268 
00269 #ifdef MDB_MONITOR_IDX
00270        mdb->mi_idx = NULL;
00271        ldap_pvt_thread_mutex_init( &mdb->mi_idx_mutex );
00272 #endif /* MDB_MONITOR_IDX */
00273 
00274        return 0;
00275 }
00276 
00277 /*
00278  * call from within mdb_db_open()
00279  */
00280 int
00281 mdb_monitor_db_open( BackendDB *be )
00282 {
00283        struct mdb_info             *mdb = (struct mdb_info *) be->be_private;
00284        Attribute            *a, *next;
00285        monitor_callback_t   *cb = NULL;
00286        int                  rc = 0;
00287        BackendInfo          *mi;
00288        monitor_extra_t             *mbe;
00289        struct berval dummy = BER_BVC("");
00290 
00291        if ( !SLAP_DBMONITORING( be ) ) {
00292               return 0;
00293        }
00294 
00295        mi = backend_info( "monitor" );
00296        if ( !mi || !mi->bi_extra ) {
00297               SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
00298               return 0;
00299        }
00300        mbe = mi->bi_extra;
00301 
00302        /* don't bother if monitor is not configured */
00303        if ( !mbe->is_configured() ) {
00304               static int warning = 0;
00305 
00306               if ( warning++ == 0 ) {
00307                      Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_db_open)
00308                             ": monitoring disabled; "
00309                             "configure monitor database to enable\n",
00310                             0, 0, 0 );
00311               }
00312 
00313               return 0;
00314        }
00315 
00316        /* alloc as many as required (plus 1 for objectClass) */
00317        a = attrs_alloc( 1 + 1 );
00318        if ( a == NULL ) {
00319               rc = 1;
00320               goto cleanup;
00321        }
00322 
00323        a->a_desc = slap_schema.si_ad_objectClass;
00324        attr_valadd( a, &oc_olmMDBDatabase->soc_cname, NULL, 1 );
00325        next = a->a_next;
00326 
00327        {
00328               struct berval bv, nbv;
00329               ber_len_t     pathlen = 0, len = 0;
00330               char          path[ MAXPATHLEN ] = { '\0' };
00331               char          *fname = mdb->mi_dbenv_home,
00332                             *ptr;
00333 
00334               len = strlen( fname );
00335               if ( fname[ 0 ] != '/' ) {
00336                      /* get full path name */
00337                      getcwd( path, sizeof( path ) );
00338                      pathlen = strlen( path );
00339 
00340                      if ( fname[ 0 ] == '.' && fname[ 1 ] == '/' ) {
00341                             fname += 2;
00342                             len -= 2;
00343                      }
00344               }
00345 
00346               bv.bv_len = pathlen + STRLENOF( "/" ) + len;
00347               ptr = bv.bv_val = ch_malloc( bv.bv_len + STRLENOF( "/" ) + 1 );
00348               if ( pathlen ) {
00349                      ptr = lutil_strncopy( ptr, path, pathlen );
00350                      ptr[ 0 ] = '/';
00351                      ptr++;
00352               }
00353               ptr = lutil_strncopy( ptr, fname, len );
00354               if ( ptr[ -1 ] != '/' ) {
00355                      ptr[ 0 ] = '/';
00356                      ptr++;
00357               }
00358               ptr[ 0 ] = '\0';
00359               
00360               attr_normalize_one( ad_olmDbDirectory, &bv, &nbv, NULL );
00361 
00362               next->a_desc = ad_olmDbDirectory;
00363               next->a_vals = ch_calloc( sizeof( struct berval ), 2 );
00364               next->a_vals[ 0 ] = bv;
00365               next->a_numvals = 1;
00366 
00367               if ( BER_BVISNULL( &nbv ) ) {
00368                      next->a_nvals = next->a_vals;
00369 
00370               } else {
00371                      next->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
00372                      next->a_nvals[ 0 ] = nbv;
00373               }
00374 
00375               next = next->a_next;
00376        }
00377 
00378        cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
00379        cb->mc_update = mdb_monitor_update;
00380 #if 0  /* uncomment if required */
00381        cb->mc_modify = mdb_monitor_modify;
00382 #endif
00383        cb->mc_free = mdb_monitor_free;
00384        cb->mc_private = (void *)mdb;
00385 
00386        /* make sure the database is registered; then add monitor attributes */
00387        rc = mbe->register_database( be, &mdb->mi_monitor.mdm_ndn );
00388        if ( rc == 0 ) {
00389               rc = mbe->register_entry_attrs( &mdb->mi_monitor.mdm_ndn, a, cb,
00390                      &dummy, 0, &dummy );
00391        }
00392 
00393 cleanup:;
00394        if ( rc != 0 ) {
00395               if ( cb != NULL ) {
00396                      ch_free( cb );
00397                      cb = NULL;
00398               }
00399 
00400               if ( a != NULL ) {
00401                      attrs_free( a );
00402                      a = NULL;
00403               }
00404        }
00405 
00406        /* store for cleanup */
00407        mdb->mi_monitor.mdm_cb = (void *)cb;
00408 
00409        /* we don't need to keep track of the attributes, because
00410         * mdb_monitor_free() takes care of everything */
00411        if ( a != NULL ) {
00412               attrs_free( a );
00413        }
00414 
00415        return rc;
00416 }
00417 
00418 /*
00419  * call from within mdb_db_close()
00420  */
00421 int
00422 mdb_monitor_db_close( BackendDB *be )
00423 {
00424        struct mdb_info             *mdb = (struct mdb_info *) be->be_private;
00425 
00426        if ( !BER_BVISNULL( &mdb->mi_monitor.mdm_ndn ) ) {
00427               BackendInfo          *mi = backend_info( "monitor" );
00428               monitor_extra_t             *mbe;
00429 
00430               if ( mi && &mi->bi_extra ) {
00431                      mbe = mi->bi_extra;
00432                      mbe->unregister_entry_callback( &mdb->mi_monitor.mdm_ndn,
00433                             (monitor_callback_t *)mdb->mi_monitor.mdm_cb,
00434                             NULL, 0, NULL );
00435               }
00436 
00437               memset( &mdb->mi_monitor, 0, sizeof( mdb->mi_monitor ) );
00438        }
00439 
00440        return 0;
00441 }
00442 
00443 /*
00444  * call from within mdb_db_destroy()
00445  */
00446 int
00447 mdb_monitor_db_destroy( BackendDB *be )
00448 {
00449 #ifdef MDB_MONITOR_IDX
00450        struct mdb_info             *mdb = (struct mdb_info *) be->be_private;
00451 
00452        /* TODO: free tree */
00453        ldap_pvt_thread_mutex_destroy( &mdb->mi_idx_mutex );
00454        avl_free( mdb->mi_idx, ch_free );
00455 #endif /* MDB_MONITOR_IDX */
00456 
00457        return 0;
00458 }
00459 
00460 #ifdef MDB_MONITOR_IDX
00461 
00462 #define MDB_MONITOR_IDX_TYPES      (4)
00463 
00464 typedef struct monitor_idx_t monitor_idx_t;
00465 
00466 struct monitor_idx_t {
00467        AttributeDescription *idx_ad;
00468        unsigned long        idx_count[MDB_MONITOR_IDX_TYPES];
00469 };
00470 
00471 static int
00472 mdb_monitor_bitmask2key( slap_mask_t bitmask )
00473 {
00474        int    key;
00475 
00476        for ( key = 0; key < 8 * (int)sizeof(slap_mask_t) && !( bitmask & 0x1U );
00477                      key++ )
00478               bitmask >>= 1;
00479 
00480        return key;
00481 }
00482 
00483 static struct berval idxbv[] = {
00484        BER_BVC( "present=" ),
00485        BER_BVC( "equality=" ),
00486        BER_BVC( "approx=" ),
00487        BER_BVC( "substr=" ),
00488        BER_BVNULL
00489 };
00490 
00491 static ber_len_t
00492 mdb_monitor_idx2len( monitor_idx_t *idx )
00493 {
00494        int           i;
00495        ber_len_t     len = 0;
00496 
00497        for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
00498               if ( idx->idx_count[ i ] != 0 ) {
00499                      len += idxbv[i].bv_len;
00500               }
00501        }
00502 
00503        return len;
00504 }
00505 
00506 static int
00507 monitor_idx_cmp( const void *p1, const void *p2 )
00508 {
00509        const monitor_idx_t  *idx1 = (const monitor_idx_t *)p1;
00510        const monitor_idx_t  *idx2 = (const monitor_idx_t *)p2;
00511 
00512        return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad );
00513 }
00514 
00515 static int
00516 monitor_idx_dup( void *p1, void *p2 )
00517 {
00518        monitor_idx_t *idx1 = (monitor_idx_t *)p1;
00519        monitor_idx_t *idx2 = (monitor_idx_t *)p2;
00520 
00521        return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ) == 0 ? -1 : 0;
00522 }
00523 
00524 int
00525 mdb_monitor_idx_add(
00526        struct mdb_info             *mdb,
00527        AttributeDescription *desc,
00528        slap_mask_t          type )
00529 {
00530        monitor_idx_t        idx_dummy = { 0 },
00531                             *idx;
00532        int                  rc = 0, key;
00533 
00534        idx_dummy.idx_ad = desc;
00535        key = mdb_monitor_bitmask2key( type ) - 1;
00536        if ( key >= MDB_MONITOR_IDX_TYPES ) {
00537               /* invalid index type */
00538               return -1;
00539        }
00540 
00541        ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
00542 
00543        idx = (monitor_idx_t *)avl_find( mdb->mi_idx,
00544               (caddr_t)&idx_dummy, monitor_idx_cmp );
00545        if ( idx == NULL ) {
00546               idx = (monitor_idx_t *)ch_calloc( sizeof( monitor_idx_t ), 1 );
00547               idx->idx_ad = desc;
00548               idx->idx_count[ key ] = 1;
00549 
00550               switch ( avl_insert( &mdb->mi_idx, (caddr_t)idx, 
00551                      monitor_idx_cmp, monitor_idx_dup ) )
00552               {
00553               case 0:
00554                      break;
00555 
00556               default:
00557                      ch_free( idx );
00558                      rc = -1;
00559               }
00560 
00561        } else {
00562               idx->idx_count[ key ]++;
00563        }
00564 
00565        ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
00566 
00567        return rc;
00568 }
00569 
00570 static int
00571 mdb_monitor_idx_apply( void *v_idx, void *v_valp )
00572 {
00573        monitor_idx_t *idx = (monitor_idx_t *)v_idx;
00574        BerVarray     *valp = (BerVarray *)v_valp;
00575 
00576        struct berval bv;
00577        char          *ptr;
00578        char          count_buf[ MDB_MONITOR_IDX_TYPES ][ SLAP_TEXT_BUFLEN ];
00579        ber_len_t     count_len[ MDB_MONITOR_IDX_TYPES ],
00580                      idx_len;
00581        int           i, num = 0;
00582 
00583        idx_len = mdb_monitor_idx2len( idx );
00584 
00585        bv.bv_len = 0;
00586        for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
00587               if ( idx->idx_count[ i ] == 0 ) {
00588                      continue;
00589               }
00590 
00591               count_len[ i ] = snprintf( count_buf[ i ],
00592                      sizeof( count_buf[ i ] ), "%lu", idx->idx_count[ i ] );
00593               bv.bv_len += count_len[ i ];
00594               num++;
00595        }
00596 
00597        bv.bv_len += idx->idx_ad->ad_cname.bv_len
00598               + num
00599               + idx_len;
00600        ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 );
00601        ptr = lutil_strcopy( ptr, idx->idx_ad->ad_cname.bv_val );
00602        for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
00603               if ( idx->idx_count[ i ] == 0 ) {
00604                      continue;
00605               }
00606 
00607               ptr[ 0 ] = '#';
00608               ++ptr;
00609               ptr = lutil_strcopy( ptr, idxbv[ i ].bv_val );
00610               ptr = lutil_strcopy( ptr, count_buf[ i ] );
00611        }
00612 
00613        ber_bvarray_add( valp, &bv );
00614 
00615        return 0;
00616 }
00617 
00618 static int
00619 mdb_monitor_idx_entry_add(
00620        struct mdb_info      *mdb,
00621        Entry         *e )
00622 {
00623        BerVarray     vals = NULL;
00624        Attribute     *a;
00625 
00626        a = attr_find( e->e_attrs, ad_olmDbNotIndexed );
00627 
00628        ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
00629 
00630        avl_apply( mdb->mi_idx, mdb_monitor_idx_apply,
00631               &vals, -1, AVL_INORDER );
00632 
00633        ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
00634 
00635        if ( vals != NULL ) {
00636               if ( a != NULL ) {
00637                      assert( a->a_nvals == a->a_vals );
00638 
00639                      ber_bvarray_free( a->a_vals );
00640 
00641               } else {
00642                      Attribute     **ap;
00643 
00644                      for ( ap = &e->e_attrs; *ap != NULL; ap = &(*ap)->a_next )
00645                             ;
00646                      *ap = attr_alloc( ad_olmDbNotIndexed );
00647                      a = *ap;
00648               }
00649               a->a_vals = vals;
00650               a->a_nvals = a->a_vals;
00651        }
00652 
00653        return 0;
00654 }
00655 
00656 #endif /* MDB_MONITOR_IDX */