Back to index

openldap  2.4.31
config.c
Go to the documentation of this file.
00001 /* config.c - bdb backend configuration file routine */
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/ctype.h>
00021 #include <ac/string.h>
00022 #include <ac/errno.h>
00023 
00024 #include "back-bdb.h"
00025 
00026 #include "config.h"
00027 
00028 #include "lutil.h"
00029 #include "ldap_rq.h"
00030 
00031 #ifdef DB_DIRTY_READ
00032 #      define SLAP_BDB_ALLOW_DIRTY_READ
00033 #endif
00034 
00035 #define bdb_cf_gen          BDB_SYMBOL(cf_gen)
00036 #define       bdb_cf_cleanup              BDB_SYMBOL(cf_cleanup)
00037 #define bdb_checkpoint             BDB_SYMBOL(checkpoint)
00038 #define bdb_online_index    BDB_SYMBOL(online_index)
00039 
00040 static ConfigDriver bdb_cf_gen;
00041 
00042 enum {
00043        BDB_CHKPT = 1,
00044        BDB_CONFIG,
00045        BDB_CRYPTFILE,
00046        BDB_CRYPTKEY,
00047        BDB_DIRECTORY,
00048        BDB_NOSYNC,
00049        BDB_DIRTYR,
00050        BDB_INDEX,
00051        BDB_LOCKD,
00052        BDB_SSTACK,
00053        BDB_MODE,
00054        BDB_PGSIZE,
00055        BDB_CHECKSUM
00056 };
00057 
00058 static ConfigTable bdbcfg[] = {
00059        { "directory", "dir", 2, 2, 0, ARG_STRING|ARG_MAGIC|BDB_DIRECTORY,
00060               bdb_cf_gen, "( OLcfgDbAt:0.1 NAME 'olcDbDirectory' "
00061                      "DESC 'Directory for database content' "
00062                      "EQUALITY caseIgnoreMatch "
00063                      "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00064        { "cachefree", "size", 2, 2, 0, ARG_ULONG|ARG_OFFSET,
00065               (void *)offsetof(struct bdb_info, bi_cache.c_minfree),
00066               "( OLcfgDbAt:1.11 NAME 'olcDbCacheFree' "
00067                      "DESC 'Number of extra entries to free when max is reached' "
00068                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00069        { "cachesize", "size", 2, 2, 0, ARG_ULONG|ARG_OFFSET,
00070               (void *)offsetof(struct bdb_info, bi_cache.c_maxsize),
00071               "( OLcfgDbAt:1.1 NAME 'olcDbCacheSize' "
00072                      "DESC 'Entry cache size in entries' "
00073                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00074        { "checkpoint", "kbyte> <min", 3, 3, 0, ARG_MAGIC|BDB_CHKPT,
00075               bdb_cf_gen, "( OLcfgDbAt:1.2 NAME 'olcDbCheckpoint' "
00076                      "DESC 'Database checkpoint interval in kbytes and minutes' "
00077                      "SYNTAX OMsDirectoryString SINGLE-VALUE )",NULL, NULL },
00078        { "checksum", NULL, 1, 2, 0, ARG_ON_OFF|ARG_MAGIC|BDB_CHECKSUM,
00079               bdb_cf_gen, "( OLcfgDbAt:1.16 NAME 'olcDbChecksum' "
00080                      "DESC 'Enable database checksum validation' "
00081                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00082        { "cryptfile", "file", 2, 2, 0, ARG_STRING|ARG_MAGIC|BDB_CRYPTFILE,
00083               bdb_cf_gen, "( OLcfgDbAt:1.13 NAME 'olcDbCryptFile' "
00084                      "DESC 'Pathname of file containing the DB encryption key' "
00085                      "SYNTAX OMsDirectoryString SINGLE-VALUE )",NULL, NULL },
00086        { "cryptkey", "key", 2, 2, 0, ARG_BERVAL|ARG_MAGIC|BDB_CRYPTKEY,
00087               bdb_cf_gen, "( OLcfgDbAt:1.14 NAME 'olcDbCryptKey' "
00088                      "DESC 'DB encryption key' "
00089                      "SYNTAX OMsOctetString SINGLE-VALUE )",NULL, NULL },
00090        { "dbconfig", "DB_CONFIG setting", 1, 0, 0, ARG_MAGIC|BDB_CONFIG,
00091               bdb_cf_gen, "( OLcfgDbAt:1.3 NAME 'olcDbConfig' "
00092                      "DESC 'BerkeleyDB DB_CONFIG configuration directives' "
00093                      "SYNTAX OMsIA5String X-ORDERED 'VALUES' )", NULL, NULL },
00094        { "dbnosync", NULL, 1, 2, 0, ARG_ON_OFF|ARG_MAGIC|BDB_NOSYNC,
00095               bdb_cf_gen, "( OLcfgDbAt:1.4 NAME 'olcDbNoSync' "
00096                      "DESC 'Disable synchronous database writes' "
00097                      "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00098        { "dbpagesize", "db> <size", 3, 3, 0, ARG_MAGIC|BDB_PGSIZE,
00099               bdb_cf_gen, "( OLcfgDbAt:1.15 NAME 'olcDbPageSize' "
00100                      "DESC 'Page size of specified DB, in Kbytes' "
00101                      "EQUALITY caseExactMatch "
00102                      "SYNTAX OMsDirectoryString )", NULL, NULL },
00103        { "dirtyread", NULL, 1, 2, 0,
00104 #ifdef SLAP_BDB_ALLOW_DIRTY_READ
00105               ARG_ON_OFF|ARG_MAGIC|BDB_DIRTYR, bdb_cf_gen,
00106 #else
00107               ARG_IGNORED, NULL,
00108 #endif
00109               "( OLcfgDbAt:1.5 NAME 'olcDbDirtyRead' "
00110               "DESC 'Allow reads of uncommitted data' "
00111               "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00112        { "dncachesize", "size", 2, 2, 0, ARG_ULONG|ARG_OFFSET,
00113               (void *)offsetof(struct bdb_info, bi_cache.c_eimax),
00114               "( OLcfgDbAt:1.12 NAME 'olcDbDNcacheSize' "
00115                      "DESC 'DN cache size' "
00116                      "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00117        { "idlcachesize", "size", 2, 2, 0, ARG_ULONG|ARG_OFFSET,
00118               (void *)offsetof(struct bdb_info, bi_idl_cache_max_size),
00119               "( OLcfgDbAt:1.6 NAME 'olcDbIDLcacheSize' "
00120               "DESC 'IDL cache size in IDLs' "
00121               "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00122        { "index", "attr> <[pres,eq,approx,sub]", 2, 3, 0, ARG_MAGIC|BDB_INDEX,
00123               bdb_cf_gen, "( OLcfgDbAt:0.2 NAME 'olcDbIndex' "
00124               "DESC 'Attribute index parameters' "
00125               "EQUALITY caseIgnoreMatch "
00126               "SYNTAX OMsDirectoryString )", NULL, NULL },
00127        { "linearindex", NULL, 1, 2, 0, ARG_ON_OFF|ARG_OFFSET,
00128               (void *)offsetof(struct bdb_info, bi_linear_index), 
00129               "( OLcfgDbAt:1.7 NAME 'olcDbLinearIndex' "
00130               "DESC 'Index attributes one at a time' "
00131               "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
00132        { "lockdetect", "policy", 2, 2, 0, ARG_MAGIC|BDB_LOCKD,
00133               bdb_cf_gen, "( OLcfgDbAt:1.8 NAME 'olcDbLockDetect' "
00134               "DESC 'Deadlock detection algorithm' "
00135               "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00136        { "mode", "mode", 2, 2, 0, ARG_MAGIC|BDB_MODE,
00137               bdb_cf_gen, "( OLcfgDbAt:0.3 NAME 'olcDbMode' "
00138               "DESC 'Unix permissions of database files' "
00139               "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
00140        { "searchstack", "depth", 2, 2, 0, ARG_INT|ARG_MAGIC|BDB_SSTACK,
00141               bdb_cf_gen, "( OLcfgDbAt:1.9 NAME 'olcDbSearchStack' "
00142               "DESC 'Depth of search stack in IDLs' "
00143               "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00144        { "shm_key", "key", 2, 2, 0, ARG_LONG|ARG_OFFSET,
00145               (void *)offsetof(struct bdb_info, bi_shm_key), 
00146               "( OLcfgDbAt:1.10 NAME 'olcDbShmKey' "
00147               "DESC 'Key for shared memory region' "
00148               "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
00149        { NULL, NULL, 0, 0, 0, ARG_IGNORED,
00150               NULL, NULL, NULL, NULL }
00151 };
00152 
00153 static ConfigOCs bdbocs[] = {
00154        {
00155 #ifdef BDB_HIER
00156               "( OLcfgDbOc:1.2 "
00157               "NAME 'olcHdbConfig' "
00158               "DESC 'HDB backend configuration' "
00159 #else
00160               "( OLcfgDbOc:1.1 "
00161               "NAME 'olcBdbConfig' "
00162               "DESC 'BDB backend configuration' "
00163 #endif
00164               "SUP olcDatabaseConfig "
00165               "MUST olcDbDirectory "
00166               "MAY ( olcDbCacheSize $ olcDbCheckpoint $ olcDbConfig $ "
00167               "olcDbCryptFile $ olcDbCryptKey $ "
00168               "olcDbNoSync $ olcDbDirtyRead $ olcDbIDLcacheSize $ "
00169               "olcDbIndex $ olcDbLinearIndex $ olcDbLockDetect $ "
00170               "olcDbMode $ olcDbSearchStack $ olcDbShmKey $ "
00171               "olcDbCacheFree $ olcDbDNcacheSize $ olcDbPageSize ) )",
00172                      Cft_Database, bdbcfg },
00173        { NULL, 0, NULL }
00174 };
00175 
00176 static slap_verbmasks bdb_lockd[] = {
00177        { BER_BVC("default"), DB_LOCK_DEFAULT },
00178        { BER_BVC("oldest"), DB_LOCK_OLDEST },
00179        { BER_BVC("random"), DB_LOCK_RANDOM },
00180        { BER_BVC("youngest"), DB_LOCK_YOUNGEST },
00181        { BER_BVC("fewest"), DB_LOCK_MINLOCKS },
00182        { BER_BVNULL, 0 }
00183 };
00184 
00185 /* perform periodic checkpoints */
00186 static void *
00187 bdb_checkpoint( void *ctx, void *arg )
00188 {
00189        struct re_s *rtask = arg;
00190        struct bdb_info *bdb = rtask->arg;
00191        
00192        TXN_CHECKPOINT( bdb->bi_dbenv, bdb->bi_txn_cp_kbyte,
00193               bdb->bi_txn_cp_min, 0 );
00194        ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
00195        ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
00196        ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
00197        return NULL;
00198 }
00199 
00200 /* reindex entries on the fly */
00201 static void *
00202 bdb_online_index( void *ctx, void *arg )
00203 {
00204        struct re_s *rtask = arg;
00205        BackendDB *be = rtask->arg;
00206        struct bdb_info *bdb = be->be_private;
00207 
00208        Connection conn = {0};
00209        OperationBuffer opbuf;
00210        Operation *op;
00211 
00212        DBC *curs;
00213        DBT key, data;
00214        DB_TXN *txn;
00215        DB_LOCK lock;
00216        ID id, nid;
00217        EntryInfo *ei;
00218        int rc, getnext = 1;
00219        int i;
00220 
00221        connection_fake_init( &conn, &opbuf, ctx );
00222        op = &opbuf.ob_op;
00223 
00224        op->o_bd = be;
00225 
00226        DBTzero( &key );
00227        DBTzero( &data );
00228        
00229        id = 1;
00230        key.data = &nid;
00231        key.size = key.ulen = sizeof(ID);
00232        key.flags = DB_DBT_USERMEM;
00233 
00234        data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
00235        data.dlen = data.ulen = 0;
00236 
00237        while ( 1 ) {
00238               if ( slapd_shutdown )
00239                      break;
00240 
00241               rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &txn, bdb->bi_db_opflags );
00242               if ( rc ) 
00243                      break;
00244               if ( getnext ) {
00245                      getnext = 0;
00246                      BDB_ID2DISK( id, &nid );
00247                      rc = bdb->bi_id2entry->bdi_db->cursor(
00248                             bdb->bi_id2entry->bdi_db, txn, &curs, bdb->bi_db_opflags );
00249                      if ( rc ) {
00250                             TXN_ABORT( txn );
00251                             break;
00252                      }
00253                      rc = curs->c_get( curs, &key, &data, DB_SET_RANGE );
00254                      curs->c_close( curs );
00255                      if ( rc ) {
00256                             TXN_ABORT( txn );
00257                             if ( rc == DB_NOTFOUND )
00258                                    rc = 0;
00259                             if ( rc == DB_LOCK_DEADLOCK ) {
00260                                    ldap_pvt_thread_yield();
00261                                    continue;
00262                             }
00263                             break;
00264                      }
00265                      BDB_DISK2ID( &nid, &id );
00266               }
00267 
00268               ei = NULL;
00269               rc = bdb_cache_find_id( op, txn, id, &ei, 0, &lock );
00270               if ( rc ) {
00271                      TXN_ABORT( txn );
00272                      if ( rc == DB_LOCK_DEADLOCK ) {
00273                             ldap_pvt_thread_yield();
00274                             continue;
00275                      }
00276                      if ( rc == DB_NOTFOUND ) {
00277                             id++;
00278                             getnext = 1;
00279                             continue;
00280                      }
00281                      break;
00282               }
00283               if ( ei->bei_e ) {
00284                      rc = bdb_index_entry( op, txn, BDB_INDEX_UPDATE_OP, ei->bei_e );
00285                      if ( rc == DB_LOCK_DEADLOCK ) {
00286                             TXN_ABORT( txn );
00287                             ldap_pvt_thread_yield();
00288                             continue;
00289                      }
00290                      if ( rc == 0 ) {
00291                             rc = TXN_COMMIT( txn, 0 );
00292                             txn = NULL;
00293                      }
00294                      if ( rc )
00295                             break;
00296               }
00297               id++;
00298               getnext = 1;
00299        }
00300 
00301        for ( i = 0; i < bdb->bi_nattrs; i++ ) {
00302               if ( bdb->bi_attrs[ i ]->ai_indexmask & BDB_INDEX_DELETING
00303                      || bdb->bi_attrs[ i ]->ai_newmask == 0 )
00304               {
00305                      continue;
00306               }
00307               bdb->bi_attrs[ i ]->ai_indexmask = bdb->bi_attrs[ i ]->ai_newmask;
00308               bdb->bi_attrs[ i ]->ai_newmask = 0;
00309        }
00310 
00311        ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
00312        ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
00313        bdb->bi_index_task = NULL;
00314        ldap_pvt_runqueue_remove( &slapd_rq, rtask );
00315        ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
00316 
00317        return NULL;
00318 }
00319 
00320 /* Cleanup loose ends after Modify completes */
00321 static int
00322 bdb_cf_cleanup( ConfigArgs *c )
00323 {
00324        struct bdb_info *bdb = c->be->be_private;
00325        int rc = 0;
00326 
00327        if ( bdb->bi_flags & BDB_UPD_CONFIG ) {
00328               if ( bdb->bi_db_config ) {
00329                      int i;
00330                      FILE *f = fopen( bdb->bi_db_config_path, "w" );
00331                      if ( f ) {
00332                             for (i=0; bdb->bi_db_config[i].bv_val; i++)
00333                                    fprintf( f, "%s\n", bdb->bi_db_config[i].bv_val );
00334                             fclose( f );
00335                      }
00336               } else {
00337                      unlink( bdb->bi_db_config_path );
00338               }
00339               bdb->bi_flags ^= BDB_UPD_CONFIG;
00340        }
00341 
00342        if ( bdb->bi_flags & BDB_DEL_INDEX ) {
00343               bdb_attr_flush( bdb );
00344               bdb->bi_flags ^= BDB_DEL_INDEX;
00345        }
00346        
00347        if ( bdb->bi_flags & BDB_RE_OPEN ) {
00348               bdb->bi_flags ^= BDB_RE_OPEN;
00349               rc = c->be->bd_info->bi_db_close( c->be, &c->reply );
00350               if ( rc == 0 )
00351                      rc = c->be->bd_info->bi_db_open( c->be, &c->reply );
00352               /* If this fails, we need to restart */
00353               if ( rc ) {
00354                      slapd_shutdown = 2;
00355                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00356                             "failed to reopen database, rc=%d", rc );
00357                      Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_cf_cleanup)
00358                             ": %s\n", c->cr_msg, 0, 0 );
00359                      rc = LDAP_OTHER;
00360               }
00361        }
00362        return rc;
00363 }
00364 
00365 static int
00366 bdb_cf_gen( ConfigArgs *c )
00367 {
00368        struct bdb_info *bdb = c->be->be_private;
00369        int rc;
00370 
00371        if ( c->op == SLAP_CONFIG_EMIT ) {
00372               rc = 0;
00373               switch( c->type ) {
00374               case BDB_MODE: {
00375                      char buf[64];
00376                      struct berval bv;
00377                      bv.bv_len = snprintf( buf, sizeof(buf), "0%o", bdb->bi_dbenv_mode );
00378                      if ( bv.bv_len > 0 && bv.bv_len < sizeof(buf) ) {
00379                             bv.bv_val = buf;
00380                             value_add_one( &c->rvalue_vals, &bv );
00381                      } else {
00382                             rc = 1;
00383                      }
00384                      } break;
00385 
00386               case BDB_CHKPT:
00387                      if ( bdb->bi_txn_cp ) {
00388                             char buf[64];
00389                             struct berval bv;
00390                             bv.bv_len = snprintf( buf, sizeof(buf), "%ld %ld",
00391                                    (long) bdb->bi_txn_cp_kbyte, (long) bdb->bi_txn_cp_min );
00392                             if ( bv.bv_len > 0 && bv.bv_len < sizeof(buf) ) {
00393                                    bv.bv_val = buf;
00394                                    value_add_one( &c->rvalue_vals, &bv );
00395                             } else {
00396                                    rc = 1;
00397                             }
00398                      } else {
00399                             rc = 1;
00400                      }
00401                      break;
00402 
00403               case BDB_CRYPTFILE:
00404                      if ( bdb->bi_db_crypt_file ) {
00405                             c->value_string = ch_strdup( bdb->bi_db_crypt_file );
00406                      } else {
00407                             rc = 1;
00408                      }
00409                      break;
00410 
00411               /* If a crypt file has been set, its contents are copied here.
00412                * But we don't want the key to be incorporated here.
00413                */
00414               case BDB_CRYPTKEY:
00415                      if ( !bdb->bi_db_crypt_file && !BER_BVISNULL( &bdb->bi_db_crypt_key )) {
00416                             value_add_one( &c->rvalue_vals, &bdb->bi_db_crypt_key );
00417                      } else {
00418                             rc = 1;
00419                      }
00420                      break;
00421 
00422               case BDB_DIRECTORY:
00423                      if ( bdb->bi_dbenv_home ) {
00424                             c->value_string = ch_strdup( bdb->bi_dbenv_home );
00425                      } else {
00426                             rc = 1;
00427                      }
00428                      break;
00429 
00430               case BDB_CONFIG:
00431                      if ( !( bdb->bi_flags & BDB_IS_OPEN )
00432                             && !bdb->bi_db_config )
00433                      {
00434                             char   buf[SLAP_TEXT_BUFLEN];
00435                             FILE *f = fopen( bdb->bi_db_config_path, "r" );
00436                             struct berval bv;
00437 
00438                             if ( f ) {
00439                                    bdb->bi_flags |= BDB_HAS_CONFIG;
00440                                    while ( fgets( buf, sizeof(buf), f )) {
00441                                           ber_str2bv( buf, 0, 1, &bv );
00442                                           if ( bv.bv_len > 0 && bv.bv_val[bv.bv_len-1] == '\n' ) {
00443                                                  bv.bv_len--;
00444                                                  bv.bv_val[bv.bv_len] = '\0';
00445                                           }
00446                                           /* shouldn't need this, but ... */
00447                                           if ( bv.bv_len > 0 && bv.bv_val[bv.bv_len-1] == '\r' ) {
00448                                                  bv.bv_len--;
00449                                                  bv.bv_val[bv.bv_len] = '\0';
00450                                           }
00451                                           ber_bvarray_add( &bdb->bi_db_config, &bv );
00452                                    }
00453                                    fclose( f );
00454                             }
00455                      }
00456                      if ( bdb->bi_db_config ) {
00457                             int i;
00458                             struct berval bv;
00459 
00460                             bv.bv_val = c->log;
00461                             for (i=0; !BER_BVISNULL(&bdb->bi_db_config[i]); i++) {
00462                                    bv.bv_len = sprintf( bv.bv_val, "{%d}%s", i,
00463                                           bdb->bi_db_config[i].bv_val );
00464                                    value_add_one( &c->rvalue_vals, &bv );
00465                             }
00466                      }
00467                      if ( !c->rvalue_vals ) rc = 1;
00468                      break;
00469 
00470               case BDB_NOSYNC:
00471                      if ( bdb->bi_dbenv_xflags & DB_TXN_NOSYNC )
00472                             c->value_int = 1;
00473                      break;
00474                      
00475               case BDB_CHECKSUM:
00476                      if ( bdb->bi_flags & BDB_CHKSUM )
00477                             c->value_int = 1;
00478                      break;
00479 
00480               case BDB_INDEX:
00481                      bdb_attr_index_unparse( bdb, &c->rvalue_vals );
00482                      if ( !c->rvalue_vals ) rc = 1;
00483                      break;
00484 
00485               case BDB_LOCKD:
00486                      rc = 1;
00487                      if ( bdb->bi_lock_detect != DB_LOCK_DEFAULT ) {
00488                             int i;
00489                             for (i=0; !BER_BVISNULL(&bdb_lockd[i].word); i++) {
00490                                    if ( bdb->bi_lock_detect == (u_int32_t)bdb_lockd[i].mask ) {
00491                                           value_add_one( &c->rvalue_vals, &bdb_lockd[i].word );
00492                                           rc = 0;
00493                                           break;
00494                                    }
00495                             }
00496                      }
00497                      break;
00498 
00499               case BDB_SSTACK:
00500                      c->value_int = bdb->bi_search_stack_depth;
00501                      break;
00502 
00503               case BDB_PGSIZE: {
00504                             struct bdb_db_pgsize *ps;
00505                             char buf[SLAP_TEXT_BUFLEN];
00506                             struct berval bv;
00507                             int rc = 1;
00508 
00509                             bv.bv_val = buf;
00510                             for ( ps = bdb->bi_pagesizes; ps; ps = ps->bdp_next ) {
00511                                    bv.bv_len = sprintf( buf, "%s %d", ps->bdp_name.bv_val,
00512                                           ps->bdp_size / 1024 );
00513                                    value_add_one( &c->rvalue_vals, &bv );
00514                                    rc = 0;
00515 
00516                             }
00517                             break;
00518                      }
00519               }
00520               return rc;
00521        } else if ( c->op == LDAP_MOD_DELETE ) {
00522               rc = 0;
00523               switch( c->type ) {
00524               case BDB_MODE:
00525 #if 0
00526                      /* FIXME: does it make any sense to change the mode,
00527                       * if we don't exec a chmod()? */
00528                      bdb->bi_dbenv_mode = SLAPD_DEFAULT_DB_MODE;
00529                      break;
00530 #endif
00531 
00532               /* single-valued no-ops */
00533               case BDB_LOCKD:
00534               case BDB_SSTACK:
00535                      break;
00536 
00537               case BDB_CHKPT:
00538                      if ( bdb->bi_txn_cp_task ) {
00539                             struct re_s *re = bdb->bi_txn_cp_task;
00540                             bdb->bi_txn_cp_task = NULL;
00541                             ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
00542                             if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
00543                                    ldap_pvt_runqueue_stoptask( &slapd_rq, re );
00544                             ldap_pvt_runqueue_remove( &slapd_rq, re );
00545                             ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
00546                      }
00547                      bdb->bi_txn_cp = 0;
00548                      break;
00549               case BDB_CONFIG:
00550                      if ( c->valx < 0 ) {
00551                             ber_bvarray_free( bdb->bi_db_config );
00552                             bdb->bi_db_config = NULL;
00553                      } else {
00554                             int i = c->valx;
00555                             ch_free( bdb->bi_db_config[i].bv_val );
00556                             for (; bdb->bi_db_config[i].bv_val; i++)
00557                                    bdb->bi_db_config[i] = bdb->bi_db_config[i+1];
00558                      }
00559                      bdb->bi_flags |= BDB_UPD_CONFIG;
00560                      c->cleanup = bdb_cf_cleanup;
00561                      break;
00562               /* Doesn't really make sense to change these on the fly;
00563                * the entire DB must be dumped and reloaded
00564                */
00565               case BDB_CRYPTFILE:
00566                      if ( bdb->bi_db_crypt_file ) {
00567                             ch_free( bdb->bi_db_crypt_file );
00568                             bdb->bi_db_crypt_file = NULL;
00569                      }
00570                      /* FALLTHRU */
00571               case BDB_CRYPTKEY:
00572                      if ( !BER_BVISNULL( &bdb->bi_db_crypt_key )) {
00573                             ch_free( bdb->bi_db_crypt_key.bv_val );
00574                             BER_BVZERO( &bdb->bi_db_crypt_key );
00575                      }
00576                      break;
00577               case BDB_DIRECTORY:
00578                      bdb->bi_flags |= BDB_RE_OPEN;
00579                      bdb->bi_flags ^= BDB_HAS_CONFIG;
00580                      ch_free( bdb->bi_dbenv_home );
00581                      bdb->bi_dbenv_home = NULL;
00582                      ch_free( bdb->bi_db_config_path );
00583                      bdb->bi_db_config_path = NULL;
00584                      c->cleanup = bdb_cf_cleanup;
00585                      ldap_pvt_thread_pool_purgekey( bdb->bi_dbenv );
00586                      break;
00587               case BDB_NOSYNC:
00588                      bdb->bi_dbenv->set_flags( bdb->bi_dbenv, DB_TXN_NOSYNC, 0 );
00589                      break;
00590               case BDB_CHECKSUM:
00591                      bdb->bi_flags &= ~BDB_CHKSUM;
00592                      break;
00593               case BDB_INDEX:
00594                      if ( c->valx == -1 ) {
00595                             int i;
00596 
00597                             /* delete all (FIXME) */
00598                             for ( i = 0; i < bdb->bi_nattrs; i++ ) {
00599                                    bdb->bi_attrs[i]->ai_indexmask |= BDB_INDEX_DELETING;
00600                             }
00601                             bdb->bi_flags |= BDB_DEL_INDEX;
00602                             c->cleanup = bdb_cf_cleanup;
00603 
00604                      } else {
00605                             struct berval bv, def = BER_BVC("default");
00606                             char *ptr;
00607 
00608                             for (ptr = c->line; !isspace( (unsigned char) *ptr ); ptr++);
00609 
00610                             bv.bv_val = c->line;
00611                             bv.bv_len = ptr - bv.bv_val;
00612                             if ( bvmatch( &bv, &def )) {
00613                                    bdb->bi_defaultmask = 0;
00614 
00615                             } else {
00616                                    int i;
00617                                    char **attrs;
00618                                    char sep;
00619 
00620                                    sep = bv.bv_val[ bv.bv_len ];
00621                                    bv.bv_val[ bv.bv_len ] = '\0';
00622                                    attrs = ldap_str2charray( bv.bv_val, "," );
00623 
00624                                    for ( i = 0; attrs[ i ]; i++ ) {
00625                                           AttributeDescription *ad = NULL;
00626                                           const char *text;
00627                                           AttrInfo *ai;
00628 
00629                                           slap_str2ad( attrs[ i ], &ad, &text );
00630                                           /* if we got here... */
00631                                           assert( ad != NULL );
00632 
00633                                           ai = bdb_attr_mask( bdb, ad );
00634                                           /* if we got here... */
00635                                           assert( ai != NULL );
00636 
00637                                           ai->ai_indexmask |= BDB_INDEX_DELETING;
00638                                           bdb->bi_flags |= BDB_DEL_INDEX;
00639                                           c->cleanup = bdb_cf_cleanup;
00640                                    }
00641 
00642                                    bv.bv_val[ bv.bv_len ] = sep;
00643                                    ldap_charray_free( attrs );
00644                             }
00645                      }
00646                      break;
00647               /* doesn't make sense on the fly; the DB file must be
00648                * recreated
00649                */
00650               case BDB_PGSIZE: {
00651                             struct bdb_db_pgsize *ps, **prev;
00652                             int i;
00653 
00654                             for ( i = 0, prev = &bdb->bi_pagesizes, ps = *prev; ps;
00655                                    prev = &ps->bdp_next, ps = ps->bdp_next, i++ ) {
00656                                    if ( c->valx == -1 || i == c->valx ) {
00657                                           *prev = ps->bdp_next;
00658                                           ch_free( ps );
00659                                           ps = *prev;
00660                                           if ( i == c->valx ) break;
00661                                    }
00662                             }
00663                      }
00664                      break;
00665               }
00666               return rc;
00667        }
00668 
00669        switch( c->type ) {
00670        case BDB_MODE:
00671               if ( ASCII_DIGIT( c->argv[1][0] ) ) {
00672                      long mode;
00673                      char *next;
00674                      errno = 0;
00675                      mode = strtol( c->argv[1], &next, 0 );
00676                      if ( errno != 0 || next == c->argv[1] || next[0] != '\0' ) {
00677                             fprintf( stderr, "%s: "
00678                                    "unable to parse mode=\"%s\".\n",
00679                                    c->log, c->argv[1] );
00680                             return 1;
00681                      }
00682                      bdb->bi_dbenv_mode = mode;
00683 
00684               } else {
00685                      char *m = c->argv[1];
00686                      int who, what, mode = 0;
00687 
00688                      if ( strlen( m ) != STRLENOF("-rwxrwxrwx") ) {
00689                             return 1;
00690                      }
00691 
00692                      if ( m[0] != '-' ) {
00693                             return 1;
00694                      }
00695 
00696                      m++;
00697                      for ( who = 0; who < 3; who++ ) {
00698                             for ( what = 0; what < 3; what++, m++ ) {
00699                                    if ( m[0] == '-' ) {
00700                                           continue;
00701                                    } else if ( m[0] != "rwx"[what] ) {
00702                                           return 1;
00703                                    }
00704                                    mode += ((1 << (2 - what)) << 3*(2 - who));
00705                             }
00706                      }
00707                      bdb->bi_dbenv_mode = mode;
00708               }
00709               break;
00710        case BDB_CHKPT: {
00711               long   l;
00712               bdb->bi_txn_cp = 1;
00713               if ( lutil_atolx( &l, c->argv[1], 0 ) != 0 ) {
00714                      fprintf( stderr, "%s: "
00715                             "invalid kbyte \"%s\" in \"checkpoint\".\n",
00716                             c->log, c->argv[1] );
00717                      return 1;
00718               }
00719               bdb->bi_txn_cp_kbyte = l;
00720               if ( lutil_atolx( &l, c->argv[2], 0 ) != 0 ) {
00721                      fprintf( stderr, "%s: "
00722                             "invalid minutes \"%s\" in \"checkpoint\".\n",
00723                             c->log, c->argv[2] );
00724                      return 1;
00725               }
00726               bdb->bi_txn_cp_min = l;
00727               /* If we're in server mode and time-based checkpointing is enabled,
00728                * submit a task to perform periodic checkpoints.
00729                */
00730               if ((slapMode & SLAP_SERVER_MODE) && bdb->bi_txn_cp_min ) {
00731                      struct re_s *re = bdb->bi_txn_cp_task;
00732                      if ( re ) {
00733                             re->interval.tv_sec = bdb->bi_txn_cp_min * 60;
00734                      } else {
00735                             if ( c->be->be_suffix == NULL || BER_BVISNULL( &c->be->be_suffix[0] ) ) {
00736                                    fprintf( stderr, "%s: "
00737                                           "\"checkpoint\" must occur after \"suffix\".\n",
00738                                           c->log );
00739                                    return 1;
00740                             }
00741                             ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
00742                             bdb->bi_txn_cp_task = ldap_pvt_runqueue_insert( &slapd_rq,
00743                                    bdb->bi_txn_cp_min * 60, bdb_checkpoint, bdb,
00744                                    LDAP_XSTRING(bdb_checkpoint), c->be->be_suffix[0].bv_val );
00745                             ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
00746                      }
00747               }
00748               } break;
00749 
00750        case BDB_CONFIG: {
00751               char *ptr = c->line;
00752               struct berval bv;
00753 
00754               if ( c->op == SLAP_CONFIG_ADD ) {
00755                      ptr += STRLENOF("dbconfig");
00756                      while (!isspace((unsigned char)*ptr)) ptr++;
00757                      while (isspace((unsigned char)*ptr)) ptr++;
00758               }
00759 
00760               if ( bdb->bi_flags & BDB_IS_OPEN ) {
00761                      bdb->bi_flags |= BDB_UPD_CONFIG;
00762                      c->cleanup = bdb_cf_cleanup;
00763               } else {
00764               /* If we're just starting up...
00765                */
00766                      FILE *f;
00767                      /* If a DB_CONFIG file exists, or we don't know the path
00768                       * to the DB_CONFIG file, ignore these directives
00769                       */
00770                      if (( bdb->bi_flags & BDB_HAS_CONFIG ) || !bdb->bi_db_config_path )
00771                             break;
00772                      f = fopen( bdb->bi_db_config_path, "a" );
00773                      if ( f ) {
00774                             /* FIXME: EBCDIC probably needs special handling */
00775                             fprintf( f, "%s\n", ptr );
00776                             fclose( f );
00777                      }
00778               }
00779               ber_str2bv( ptr, 0, 1, &bv );
00780               ber_bvarray_add( &bdb->bi_db_config, &bv );
00781               }
00782               break;
00783 
00784        case BDB_CRYPTFILE:
00785               rc = lutil_get_filed_password( c->value_string, &bdb->bi_db_crypt_key );
00786               if ( rc == 0 ) {
00787                      bdb->bi_db_crypt_file = c->value_string;
00788               }
00789               break;
00790 
00791        /* Cannot set key if file was already set */
00792        case BDB_CRYPTKEY:
00793               if ( bdb->bi_db_crypt_file ) {
00794                      rc = 1;
00795               } else {
00796                      bdb->bi_db_crypt_key = c->value_bv;
00797               }
00798               break;
00799 
00800        case BDB_DIRECTORY: {
00801               FILE *f;
00802               char *ptr, *testpath;
00803               int len;
00804 
00805               len = strlen( c->value_string );
00806               testpath = ch_malloc( len + STRLENOF(LDAP_DIRSEP) + STRLENOF("DUMMY") + 1 );
00807               ptr = lutil_strcopy( testpath, c->value_string );
00808               *ptr++ = LDAP_DIRSEP[0];
00809               strcpy( ptr, "DUMMY" );
00810               f = fopen( testpath, "w" );
00811               if ( f ) {
00812                      fclose( f );
00813                      unlink( testpath );
00814               }
00815               ch_free( testpath );
00816               if ( !f ) {
00817                      snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: invalid path: %s",
00818                             c->log, strerror( errno ));
00819                      Debug( LDAP_DEBUG_ANY, "%s\n", c->cr_msg, 0, 0 );
00820                      return -1;
00821               }
00822 
00823               if ( bdb->bi_dbenv_home )
00824                      ch_free( bdb->bi_dbenv_home );
00825               bdb->bi_dbenv_home = c->value_string;
00826 
00827               /* See if a DB_CONFIG file already exists here */
00828               if ( bdb->bi_db_config_path )
00829                      ch_free( bdb->bi_db_config_path );
00830               bdb->bi_db_config_path = ch_malloc( len +
00831                      STRLENOF(LDAP_DIRSEP) + STRLENOF("DB_CONFIG") + 1 );
00832               ptr = lutil_strcopy( bdb->bi_db_config_path, bdb->bi_dbenv_home );
00833               *ptr++ = LDAP_DIRSEP[0];
00834               strcpy( ptr, "DB_CONFIG" );
00835 
00836               f = fopen( bdb->bi_db_config_path, "r" );
00837               if ( f ) {
00838                      bdb->bi_flags |= BDB_HAS_CONFIG;
00839                      fclose(f);
00840               }
00841               }
00842               break;
00843 
00844        case BDB_NOSYNC:
00845               if ( c->value_int )
00846                      bdb->bi_dbenv_xflags |= DB_TXN_NOSYNC;
00847               else
00848                      bdb->bi_dbenv_xflags &= ~DB_TXN_NOSYNC;
00849               if ( bdb->bi_flags & BDB_IS_OPEN ) {
00850                      bdb->bi_dbenv->set_flags( bdb->bi_dbenv, DB_TXN_NOSYNC,
00851                             c->value_int );
00852               }
00853               break;
00854 
00855        case BDB_CHECKSUM:
00856               if ( c->value_int )
00857                      bdb->bi_flags |= BDB_CHKSUM;
00858               else
00859                      bdb->bi_flags &= ~BDB_CHKSUM;
00860               break;
00861 
00862        case BDB_INDEX:
00863               rc = bdb_attr_index_config( bdb, c->fname, c->lineno,
00864                      c->argc - 1, &c->argv[1], &c->reply);
00865 
00866               if( rc != LDAP_SUCCESS ) return 1;
00867               if (( bdb->bi_flags & BDB_IS_OPEN ) && !bdb->bi_index_task ) {
00868                      /* Start the task as soon as we finish here. Set a long
00869                       * interval (10 hours) so that it only gets scheduled once.
00870                       */
00871                      if ( c->be->be_suffix == NULL || BER_BVISNULL( &c->be->be_suffix[0] ) ) {
00872                             fprintf( stderr, "%s: "
00873                                    "\"index\" must occur after \"suffix\".\n",
00874                                    c->log );
00875                             return 1;
00876                      }
00877                      ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
00878                      bdb->bi_index_task = ldap_pvt_runqueue_insert( &slapd_rq, 36000,
00879                             bdb_online_index, c->be,
00880                             LDAP_XSTRING(bdb_online_index), c->be->be_suffix[0].bv_val );
00881                      ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
00882               }
00883               break;
00884 
00885        case BDB_LOCKD:
00886               rc = verb_to_mask( c->argv[1], bdb_lockd );
00887               if ( BER_BVISNULL(&bdb_lockd[rc].word) ) {
00888                      fprintf( stderr, "%s: "
00889                             "bad policy (%s) in \"lockDetect <policy>\" line\n",
00890                             c->log, c->argv[1] );
00891                      return 1;
00892               }
00893               bdb->bi_lock_detect = (u_int32_t)rc;
00894               break;
00895 
00896        case BDB_SSTACK:
00897               if ( c->value_int < MINIMUM_SEARCH_STACK_DEPTH ) {
00898                      fprintf( stderr,
00899               "%s: depth %d too small, using %d\n",
00900                      c->log, c->value_int, MINIMUM_SEARCH_STACK_DEPTH );
00901                      c->value_int = MINIMUM_SEARCH_STACK_DEPTH;
00902               }
00903               bdb->bi_search_stack_depth = c->value_int;
00904               break;
00905 
00906        case BDB_PGSIZE: {
00907               struct bdb_db_pgsize *ps, **prev;
00908               int i, s;
00909               
00910               s = atoi(c->argv[2]);
00911               if ( s < 1 || s > 64 ) {
00912                      snprintf( c->cr_msg, sizeof( c->cr_msg ),
00913                             "%s: size must be > 0 and <= 64: %d",
00914                             c->log, s );
00915                      Debug( LDAP_DEBUG_ANY, "%s\n", c->cr_msg, 0, 0 );
00916                      return -1;
00917               }
00918               i = strlen(c->argv[1]);
00919               ps = ch_malloc( sizeof(struct bdb_db_pgsize) + i + 1 );
00920               ps->bdp_next = NULL;
00921               ps->bdp_name.bv_len = i;
00922               ps->bdp_name.bv_val = (char *)(ps+1);
00923               strcpy( ps->bdp_name.bv_val, c->argv[1] );
00924               ps->bdp_size = s * 1024;
00925               for ( prev = &bdb->bi_pagesizes; *prev; prev = &(*prev)->bdp_next )
00926                      ;
00927               *prev = ps;
00928               }
00929               break;
00930        }
00931        return 0;
00932 }
00933 
00934 int bdb_back_init_cf( BackendInfo *bi )
00935 {
00936        int rc;
00937        bi->bi_cf_ocs = bdbocs;
00938 
00939        rc = config_register_schema( bdbcfg, bdbocs );
00940        if ( rc ) return rc;
00941        return 0;
00942 }