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