1 /*
   2 ** Copyright (c) 1999-2003, 2009 Proofpoint, Inc. and its suppliers.
   3 **      All rights reserved.
   4 **
   5 ** By using this file, you agree to the terms and conditions set
   6 ** forth in the LICENSE file which can be found at the top level of
   7 ** the sendmail distribution.
   8 */
   9 
  10 #include <sm/gen.h>
  11 SM_RCSID("@(#)$Id: smdb2.c,v 8.83 2013-11-22 20:51:49 ca Exp $")
  12 
  13 #include <fcntl.h>
  14 #include <stdlib.h>
  15 #include <unistd.h>
  16 
  17 
  18 #include <sendmail/sendmail.h>
  19 #include <libsmdb/smdb.h>
  20 
  21 #if (DB_VERSION_MAJOR >= 2)
  22 
  23 # define SMDB2_FILE_EXTENSION "db"
  24 
  25 struct smdb_db2_database
  26 {
  27         DB      *smdb2_db;
  28         int     smdb2_lock_fd;
  29 };
  30 typedef struct smdb_db2_database SMDB_DB2_DATABASE;
  31 
  32 /*
  33 **  SMDB_TYPE_TO_DB2_TYPE -- Translates smdb database type to db2 type.
  34 **
  35 **      Parameters:
  36 **              type -- The type to translate.
  37 **
  38 **      Returns:
  39 **              The DB2 type that corresponsds to the passed in SMDB type.
  40 **              Returns -1 if there is no equivalent type.
  41 **
  42 */
  43 
  44 DBTYPE
  45 smdb_type_to_db2_type(type)
  46         SMDB_DBTYPE type;
  47 {
  48         if (type == SMDB_TYPE_DEFAULT)
  49                 return DB_HASH;
  50 
  51         if (strncmp(type, SMDB_TYPE_HASH, SMDB_TYPE_HASH_LEN) == 0)
  52                 return DB_HASH;
  53 
  54         if (strncmp(type, SMDB_TYPE_BTREE, SMDB_TYPE_BTREE_LEN) == 0)
  55                 return DB_BTREE;
  56 
  57         return DB_UNKNOWN;
  58 }
  59 /*
  60 **  DB2_ERROR_TO_SMDB -- Translates db2 errors to smdbe errors
  61 **
  62 **      Parameters:
  63 **              error -- The error to translate.
  64 **
  65 **      Returns:
  66 **              The SMDBE error corresponding to the db2 error.
  67 **              If we don't have a corresponding error, it returs errno.
  68 **
  69 */
  70 
  71 int
  72 db2_error_to_smdb(error)
  73         int error;
  74 {
  75         int result;
  76 
  77         switch (error)
  78         {
  79 # ifdef DB_INCOMPLETE
  80                 case DB_INCOMPLETE:
  81                         result = SMDBE_INCOMPLETE;
  82                         break;
  83 # endif /* DB_INCOMPLETE */
  84 
  85 # ifdef DB_NOTFOUND
  86                 case DB_NOTFOUND:
  87                         result = SMDBE_NOT_FOUND;
  88                         break;
  89 # endif /* DB_NOTFOUND */
  90 
  91 # ifdef DB_KEYEMPTY
  92                 case DB_KEYEMPTY:
  93                         result = SMDBE_KEY_EMPTY;
  94                         break;
  95 # endif /* DB_KEYEMPTY */
  96 
  97 # ifdef DB_KEYEXIST
  98                 case DB_KEYEXIST:
  99                         result = SMDBE_KEY_EXIST;
 100                         break;
 101 # endif /* DB_KEYEXIST */
 102 
 103 # ifdef DB_LOCK_DEADLOCK
 104                 case DB_LOCK_DEADLOCK:
 105                         result = SMDBE_LOCK_DEADLOCK;
 106                         break;
 107 # endif /* DB_LOCK_DEADLOCK */
 108 
 109 # ifdef DB_LOCK_NOTGRANTED
 110                 case DB_LOCK_NOTGRANTED:
 111                         result = SMDBE_LOCK_NOT_GRANTED;
 112                         break;
 113 # endif /* DB_LOCK_NOTGRANTED */
 114 
 115 # ifdef DB_LOCK_NOTHELD
 116                 case DB_LOCK_NOTHELD:
 117                         result = SMDBE_LOCK_NOT_HELD;
 118                         break;
 119 # endif /* DB_LOCK_NOTHELD */
 120 
 121 # ifdef DB_RUNRECOVERY
 122                 case DB_RUNRECOVERY:
 123                         result = SMDBE_RUN_RECOVERY;
 124                         break;
 125 # endif /* DB_RUNRECOVERY */
 126 
 127 # ifdef DB_OLD_VERSION
 128                 case DB_OLD_VERSION:
 129                         result = SMDBE_OLD_VERSION;
 130                         break;
 131 # endif /* DB_OLD_VERSION */
 132 
 133                 case 0:
 134                         result = SMDBE_OK;
 135                         break;
 136 
 137                 default:
 138                         result = error;
 139         }
 140         return result;
 141 }
 142 /*
 143 **  SMDB_PUT_FLAGS_TO_DB2_FLAGS -- Translates smdb put flags to db2 put flags.
 144 **
 145 **      Parameters:
 146 **              flags -- The flags to translate.
 147 **
 148 **      Returns:
 149 **              The db2 flags that are equivalent to the smdb flags.
 150 **
 151 **      Notes:
 152 **              Any invalid flags are ignored.
 153 **
 154 */
 155 
 156 unsigned int
 157 smdb_put_flags_to_db2_flags(flags)
 158         SMDB_FLAG flags;
 159 {
 160         int return_flags;
 161 
 162         return_flags = 0;
 163 
 164         if (bitset(SMDBF_NO_OVERWRITE, flags))
 165                 return_flags |= DB_NOOVERWRITE;
 166 
 167         return return_flags;
 168 }
 169 /*
 170 **  SMDB_CURSOR_GET_FLAGS_TO_DB2 -- Translates smdb cursor get flags to db2
 171 **      getflags.
 172 **
 173 **      Parameters:
 174 **              flags -- The flags to translate.
 175 **
 176 **      Returns:
 177 **              The db2 flags that are equivalent to the smdb flags.
 178 **
 179 **      Notes:
 180 **              -1 is returned if flag is unknown.
 181 **
 182 */
 183 
 184 int
 185 smdb_cursor_get_flags_to_db2(flags)
 186         SMDB_FLAG flags;
 187 {
 188         switch (flags)
 189         {
 190                 case SMDB_CURSOR_GET_FIRST:
 191                         return DB_FIRST;
 192 
 193                 case SMDB_CURSOR_GET_LAST:
 194                         return DB_LAST;
 195 
 196                 case SMDB_CURSOR_GET_NEXT:
 197                         return DB_NEXT;
 198 
 199                 case SMDB_CURSOR_GET_RANGE:
 200                         return DB_SET_RANGE;
 201 
 202                 default:
 203                         return -1;
 204         }
 205 }
 206 
 207 /*
 208 **  Except for smdb_db_open, the rest of these functions correspond to the
 209 **  interface laid out in smdb.h.
 210 */
 211 
 212 SMDB_DB2_DATABASE *
 213 smdb2_malloc_database()
 214 {
 215         SMDB_DB2_DATABASE *db2;
 216 
 217         db2 = (SMDB_DB2_DATABASE *) malloc(sizeof(SMDB_DB2_DATABASE));
 218         if (db2 != NULL)
 219                 db2->smdb2_lock_fd = -1;
 220 
 221         return db2;
 222 }
 223 
 224 int
 225 smdb2_close(database)
 226         SMDB_DATABASE *database;
 227 {
 228         int result;
 229         SMDB_DB2_DATABASE *db2 = (SMDB_DB2_DATABASE *) database->smdb_impl;
 230         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
 231 
 232         result = db2_error_to_smdb(db->close(db, 0));
 233         if (db2->smdb2_lock_fd != -1)
 234                 close(db2->smdb2_lock_fd);
 235 
 236         free(db2);
 237         database->smdb_impl = NULL;
 238 
 239         return result;
 240 }
 241 
 242 int
 243 smdb2_del(database, key, flags)
 244         SMDB_DATABASE *database;
 245         SMDB_DBENT *key;
 246         unsigned int flags;
 247 {
 248         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
 249         DBT dbkey;
 250 
 251         (void) memset(&dbkey, '\0', sizeof dbkey);
 252         dbkey.data = key->data;
 253         dbkey.size = key->size;
 254         return db2_error_to_smdb(db->del(db, NULL, &dbkey, flags));
 255 }
 256 
 257 int
 258 smdb2_fd(database, fd)
 259         SMDB_DATABASE *database;
 260         int *fd;
 261 {
 262         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
 263 
 264         return db2_error_to_smdb(db->fd(db, fd));
 265 }
 266 
 267 int
 268 smdb2_lockfd(database)
 269         SMDB_DATABASE *database;
 270 {
 271         SMDB_DB2_DATABASE *db2 = (SMDB_DB2_DATABASE *) database->smdb_impl;
 272 
 273         return db2->smdb2_lock_fd;
 274 }
 275 
 276 int
 277 smdb2_get(database, key, data, flags)
 278         SMDB_DATABASE *database;
 279         SMDB_DBENT *key;
 280         SMDB_DBENT *data;
 281         unsigned int flags;
 282 {
 283         int result;
 284         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
 285         DBT dbkey, dbdata;
 286 
 287         (void) memset(&dbdata, '\0', sizeof dbdata);
 288         (void) memset(&dbkey, '\0', sizeof dbkey);
 289         dbkey.data = key->data;
 290         dbkey.size = key->size;
 291 
 292         result = db->get(db, NULL, &dbkey, &dbdata, flags);
 293         data->data = dbdata.data;
 294         data->size = dbdata.size;
 295         return db2_error_to_smdb(result);
 296 }
 297 
 298 int
 299 smdb2_put(database, key, data, flags)
 300         SMDB_DATABASE *database;
 301         SMDB_DBENT *key;
 302         SMDB_DBENT *data;
 303         unsigned int flags;
 304 {
 305         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
 306         DBT dbkey, dbdata;
 307 
 308         (void) memset(&dbdata, '\0', sizeof dbdata);
 309         (void) memset(&dbkey, '\0', sizeof dbkey);
 310         dbkey.data = key->data;
 311         dbkey.size = key->size;
 312         dbdata.data = data->data;
 313         dbdata.size = data->size;
 314 
 315         return db2_error_to_smdb(db->put(db, NULL, &dbkey, &dbdata,
 316                                          smdb_put_flags_to_db2_flags(flags)));
 317 }
 318 
 319 
 320 int
 321 smdb2_set_owner(database, uid, gid)
 322         SMDB_DATABASE *database;
 323         uid_t uid;
 324         gid_t gid;
 325 {
 326 # if HASFCHOWN
 327         int fd;
 328         int result;
 329         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
 330 
 331         result = db->fd(db, &fd);
 332         if (result != 0)
 333                 return result;
 334 
 335         result = fchown(fd, uid, gid);
 336         if (result < 0)
 337                 return errno;
 338 # endif /* HASFCHOWN */
 339 
 340         return SMDBE_OK;
 341 }
 342 
 343 int
 344 smdb2_sync(database, flags)
 345         SMDB_DATABASE *database;
 346         unsigned int flags;
 347 {
 348         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
 349 
 350         return db2_error_to_smdb(db->sync(db, flags));
 351 }
 352 
 353 int
 354 smdb2_cursor_close(cursor)
 355         SMDB_CURSOR *cursor;
 356 {
 357         int ret;
 358         DBC *dbc = (DBC *) cursor->smdbc_impl;
 359 
 360         ret = db2_error_to_smdb(dbc->c_close(dbc));
 361         free(cursor);
 362         return ret;
 363 }
 364 
 365 int
 366 smdb2_cursor_del(cursor, flags)
 367         SMDB_CURSOR *cursor;
 368         SMDB_FLAG flags;
 369 {
 370         DBC *dbc = (DBC *) cursor->smdbc_impl;
 371 
 372         return db2_error_to_smdb(dbc->c_del(dbc, 0));
 373 }
 374 
 375 int
 376 smdb2_cursor_get(cursor, key, value, flags)
 377         SMDB_CURSOR *cursor;
 378         SMDB_DBENT *key;
 379         SMDB_DBENT *value;
 380         SMDB_FLAG flags;
 381 {
 382         int db2_flags;
 383         int result;
 384         DBC *dbc = (DBC *) cursor->smdbc_impl;
 385         DBT dbkey, dbdata;
 386 
 387         (void) memset(&dbdata, '\0', sizeof dbdata);
 388         (void) memset(&dbkey, '\0', sizeof dbkey);
 389 
 390         db2_flags = smdb_cursor_get_flags_to_db2(flags);
 391         result = dbc->c_get(dbc, &dbkey, &dbdata, db2_flags);
 392         if (result == DB_NOTFOUND)
 393                 return SMDBE_LAST_ENTRY;
 394         key->data = dbkey.data;
 395         key->size = dbkey.size;
 396         value->data = dbdata.data;
 397         value->size = dbdata.size;
 398         return db2_error_to_smdb(result);
 399 }
 400 
 401 int
 402 smdb2_cursor_put(cursor, key, value, flags)
 403         SMDB_CURSOR *cursor;
 404         SMDB_DBENT *key;
 405         SMDB_DBENT *value;
 406         SMDB_FLAG flags;
 407 {
 408         DBC *dbc = (DBC *) cursor->smdbc_impl;
 409         DBT dbkey, dbdata;
 410 
 411         (void) memset(&dbdata, '\0', sizeof dbdata);
 412         (void) memset(&dbkey, '\0', sizeof dbkey);
 413         dbkey.data = key->data;
 414         dbkey.size = key->size;
 415         dbdata.data = value->data;
 416         dbdata.size = value->size;
 417 
 418         return db2_error_to_smdb(dbc->c_put(dbc, &dbkey, &dbdata, 0));
 419 }
 420 
 421 int
 422 smdb2_cursor(database, cursor, flags)
 423         SMDB_DATABASE *database;
 424         SMDB_CURSOR **cursor;
 425         SMDB_FLAG flags;
 426 {
 427         int result;
 428         DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
 429         DBC *db2_cursor;
 430 
 431 # if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6
 432         result = db->cursor(db, NULL, &db2_cursor, 0);
 433 # else /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
 434         result = db->cursor(db, NULL, &db2_cursor);
 435 # endif /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
 436         if (result != 0)
 437                 return db2_error_to_smdb(result);
 438 
 439         *cursor = (SMDB_CURSOR *) malloc(sizeof(SMDB_CURSOR));
 440         if (*cursor == NULL)
 441                 return SMDBE_MALLOC;
 442 
 443         (*cursor)->smdbc_close = smdb2_cursor_close;
 444         (*cursor)->smdbc_del = smdb2_cursor_del;
 445         (*cursor)->smdbc_get = smdb2_cursor_get;
 446         (*cursor)->smdbc_put = smdb2_cursor_put;
 447         (*cursor)->smdbc_impl = db2_cursor;
 448 
 449         return SMDBE_OK;
 450 }
 451 
 452 # if DB_VERSION_MAJOR == 2
 453 static int
 454 smdb_db_open_internal(db_name, db_type, db_flags, db_params, db)
 455         char *db_name;
 456         DBTYPE db_type;
 457         int db_flags;
 458         SMDB_DBPARAMS *db_params;
 459         DB **db;
 460 {
 461         void *params;
 462         DB_INFO db_info;
 463 
 464         params = NULL;
 465         (void) memset(&db_info, '\0', sizeof db_info);
 466         if (db_params != NULL)
 467         {
 468                 db_info.db_cachesize = db_params->smdbp_cache_size;
 469                 if (db_type == DB_HASH)
 470                         db_info.h_nelem = db_params->smdbp_num_elements;
 471                 if (db_params->smdbp_allow_dup)
 472                         db_info.flags |= DB_DUP;
 473                 params = &db_info;
 474         }
 475         return db_open(db_name, db_type, db_flags, DBMMODE, NULL, params, db);
 476 }
 477 # endif /* DB_VERSION_MAJOR == 2 */
 478 
 479 # if DB_VERSION_MAJOR > 2
 480 static int
 481 smdb_db_open_internal(db_name, db_type, db_flags, db_params, db)
 482         char *db_name;
 483         DBTYPE db_type;
 484         int db_flags;
 485         SMDB_DBPARAMS *db_params;
 486         DB **db;
 487 {
 488         int result;
 489 
 490         result = db_create(db, NULL, 0);
 491         if (result != 0 || *db == NULL)
 492                 return result;
 493 
 494         if (db_params != NULL)
 495         {
 496                 result = (*db)->set_cachesize(*db, 0,
 497                                               db_params->smdbp_cache_size, 0);
 498                 if (result != 0)
 499                 {
 500                         (void) (*db)->close((*db), 0);
 501                         *db = NULL;
 502                         return db2_error_to_smdb(result);
 503                 }
 504                 if (db_type == DB_HASH)
 505                 {
 506                         result = (*db)->set_h_nelem(*db, db_params->smdbp_num_elements);
 507                         if (result != 0)
 508                         {
 509                                 (void) (*db)->close(*db, 0);
 510                                 *db = NULL;
 511                                 return db2_error_to_smdb(result);
 512                         }
 513                 }
 514                 if (db_params->smdbp_allow_dup)
 515                 {
 516                         result = (*db)->set_flags(*db, DB_DUP);
 517                         if (result != 0)
 518                         {
 519                                 (void) (*db)->close(*db, 0);
 520                                 *db = NULL;
 521                                 return db2_error_to_smdb(result);
 522                         }
 523                 }
 524         }
 525 
 526         result = (*db)->open(*db,
 527                              DBTXN      /* transaction for DB 4.1 */
 528                              db_name, NULL, db_type, db_flags, DBMMODE);
 529         if (result != 0)
 530         {
 531                 (void) (*db)->close(*db, 0);
 532                 *db = NULL;
 533         }
 534         return db2_error_to_smdb(result);
 535 }
 536 # endif /* DB_VERSION_MAJOR > 2 */
 537 /*
 538 **  SMDB_DB_OPEN -- Opens a db database.
 539 **
 540 **      Parameters:
 541 **              database -- An unallocated database pointer to a pointer.
 542 **              db_name -- The name of the database without extension.
 543 **              mode -- File permisions for a created database.
 544 **              mode_mask -- Mode bits that must match on an opened database.
 545 **              sff -- Flags for safefile.
 546 **              type -- The type of database to open
 547 **                      See smdb_type_to_db2_type for valid types.
 548 **              user_info -- User information for file permissions.
 549 **              db_params --
 550 **                      An SMDB_DBPARAMS struct including params. These
 551 **                      are processed according to the type of the
 552 **                      database. Currently supported params (only for
 553 **                      HASH type) are:
 554 **                         num_elements
 555 **                         cache_size
 556 **
 557 **      Returns:
 558 **              SMDBE_OK -- Success, other errno:
 559 **              SMDBE_MALLOC -- Cannot allocate memory.
 560 **              SMDBE_BAD_OPEN -- db_open didn't return an error, but
 561 **                               somehow the DB pointer is NULL.
 562 **              Anything else: translated error from db2
 563 */
 564 
 565 int
 566 smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info, db_params)
 567         SMDB_DATABASE **database;
 568         char *db_name;
 569         int mode;
 570         int mode_mask;
 571         long sff;
 572         SMDB_DBTYPE type;
 573         SMDB_USER_INFO *user_info;
 574         SMDB_DBPARAMS *db_params;
 575 {
 576         bool lockcreated = false;
 577         int result;
 578         int db_flags;
 579         int lock_fd;
 580         int db_fd;
 581         int major_v, minor_v, patch_v;
 582         SMDB_DATABASE *smdb_db;
 583         SMDB_DB2_DATABASE *db2;
 584         DB *db;
 585         DBTYPE db_type;
 586         struct stat stat_info;
 587         char db_file_name[MAXPATHLEN];
 588 
 589         (void) db_version(&major_v, &minor_v, &patch_v);
 590         if (major_v != DB_VERSION_MAJOR || minor_v != DB_VERSION_MINOR)
 591                 return SMDBE_VERSION_MISMATCH;
 592 
 593         *database = NULL;
 594 
 595         result = smdb_add_extension(db_file_name, sizeof db_file_name,
 596                                     db_name, SMDB2_FILE_EXTENSION);
 597         if (result != SMDBE_OK)
 598                 return result;
 599 
 600         result = smdb_setup_file(db_name, SMDB2_FILE_EXTENSION,
 601                                  mode_mask, sff, user_info, &stat_info);
 602         if (result != SMDBE_OK)
 603                 return result;
 604 
 605         lock_fd = -1;
 606 
 607         if (stat_info.st_mode == ST_MODE_NOFILE &&
 608             bitset(mode, O_CREAT))
 609                 lockcreated = true;
 610 
 611         result = smdb_lock_file(&lock_fd, db_name, mode, sff,
 612                                 SMDB2_FILE_EXTENSION);
 613         if (result != SMDBE_OK)
 614                 return result;
 615 
 616         if (lockcreated)
 617         {
 618                 mode |= O_TRUNC;
 619                 mode &= ~(O_CREAT|O_EXCL);
 620         }
 621 
 622         smdb_db = smdb_malloc_database();
 623         db2 = smdb2_malloc_database();
 624         if (db2 == NULL || smdb_db == NULL)
 625         {
 626                 smdb_unlock_file(lock_fd);
 627                 smdb_free_database(smdb_db);    /* ok to be NULL */
 628                 if (db2 != NULL)
 629                         free(db2);
 630                 return SMDBE_MALLOC;
 631         }
 632 
 633         db2->smdb2_lock_fd = lock_fd;
 634 
 635         db_type = smdb_type_to_db2_type(type);
 636 
 637         db = NULL;
 638 
 639         db_flags = 0;
 640         if (bitset(O_CREAT, mode))
 641                 db_flags |= DB_CREATE;
 642         if (bitset(O_TRUNC, mode))
 643                 db_flags |= DB_TRUNCATE;
 644         if (mode == O_RDONLY)
 645                 db_flags |= DB_RDONLY;
 646         SM_DB_FLAG_ADD(db_flags);
 647 
 648         result = smdb_db_open_internal(db_file_name, db_type,
 649                                        db_flags, db_params, &db);
 650 
 651         if (result == 0 && db != NULL)
 652         {
 653                 result = db->fd(db, &db_fd);
 654                 if (result == 0)
 655                         result = SMDBE_OK;
 656         }
 657         else
 658         {
 659                 /* Try and narrow down on the problem */
 660                 if (result != 0)
 661                         result = db2_error_to_smdb(result);
 662                 else
 663                         result = SMDBE_BAD_OPEN;
 664         }
 665 
 666         if (result == SMDBE_OK)
 667                 result = smdb_filechanged(db_name, SMDB2_FILE_EXTENSION, db_fd,
 668                                           &stat_info);
 669 
 670         if (result == SMDBE_OK)
 671         {
 672                 /* Everything is ok. Setup driver */
 673                 db2->smdb2_db = db;
 674 
 675                 smdb_db->smdb_close = smdb2_close;
 676                 smdb_db->smdb_del = smdb2_del;
 677                 smdb_db->smdb_fd = smdb2_fd;
 678                 smdb_db->smdb_lockfd = smdb2_lockfd;
 679                 smdb_db->smdb_get = smdb2_get;
 680                 smdb_db->smdb_put = smdb2_put;
 681                 smdb_db->smdb_set_owner = smdb2_set_owner;
 682                 smdb_db->smdb_sync = smdb2_sync;
 683                 smdb_db->smdb_cursor = smdb2_cursor;
 684                 smdb_db->smdb_impl = db2;
 685 
 686                 *database = smdb_db;
 687 
 688                 return SMDBE_OK;
 689         }
 690 
 691         if (db != NULL)
 692                 db->close(db, 0);
 693 
 694         smdb_unlock_file(db2->smdb2_lock_fd);
 695         free(db2);
 696         smdb_free_database(smdb_db);
 697 
 698         return result;
 699 }
 700 
 701 #endif /* (DB_VERSION_MAJOR >= 2) */