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