1 /* 2 ** Copyright (c) 1999-2000 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.2 2000/08/24 17:08:00 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 254 return db2_error_to_smdb(db->del(db, NULL, &key->db, 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 277 int 278 smdb2_get(database, key, data, flags) 279 SMDB_DATABASE *database; 280 SMDB_DBENT *key; 281 SMDB_DBENT *data; 282 u_int flags; 283 { 284 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; 285 286 return db2_error_to_smdb(db->get(db, NULL, &key->db, &data->db, flags)); 287 } 288 289 int 290 smdb2_put(database, key, data, flags) 291 SMDB_DATABASE *database; 292 SMDB_DBENT *key; 293 SMDB_DBENT *data; 294 u_int flags; 295 { 296 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; 297 298 return db2_error_to_smdb(db->put(db, NULL, &key->db, &data->db, 299 smdb_put_flags_to_db2_flags(flags))); 300 } 301 302 303 int 304 smdb2_set_owner(database, uid, gid) 305 SMDB_DATABASE *database; 306 uid_t uid; 307 gid_t gid; 308 { 309 # if HASFCHOWN 310 int fd; 311 int result; 312 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; 313 314 result = db->fd(db, &fd); 315 if (result != 0) 316 return result; 317 318 result = fchown(fd, uid, gid); 319 if (result < 0) 320 return errno; 321 # endif /* HASFCHOWN */ 322 323 return SMDBE_OK; 324 } 325 326 int 327 smdb2_sync(database, flags) 328 SMDB_DATABASE *database; 329 u_int flags; 330 { 331 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; 332 333 return db2_error_to_smdb(db->sync(db, flags)); 334 } 335 336 int 337 smdb2_cursor_close(cursor) 338 SMDB_CURSOR *cursor; 339 { 340 DBC *dbc = (DBC *) cursor->smdbc_impl; 341 342 return db2_error_to_smdb(dbc->c_close(dbc)); 343 } 344 345 int 346 smdb2_cursor_del(cursor, flags) 347 SMDB_CURSOR *cursor; 348 SMDB_FLAG flags; 349 { 350 DBC *dbc = (DBC *) cursor->smdbc_impl; 351 352 return db2_error_to_smdb(dbc->c_del(dbc, 0)); 353 } 354 355 int 356 smdb2_cursor_get(cursor, key, value, flags) 357 SMDB_CURSOR *cursor; 358 SMDB_DBENT *key; 359 SMDB_DBENT *value; 360 SMDB_FLAG flags; 361 { 362 int db2_flags; 363 int result; 364 DBC *dbc = (DBC *) cursor->smdbc_impl; 365 366 db2_flags = smdb_cursor_get_flags_to_db2(flags); 367 result = dbc->c_get(dbc, &key->db, &value->db, db2_flags); 368 if (result == DB_NOTFOUND) 369 return SMDBE_LAST_ENTRY; 370 return db2_error_to_smdb(result); 371 } 372 373 int 374 smdb2_cursor_put(cursor, key, value, flags) 375 SMDB_CURSOR *cursor; 376 SMDB_DBENT *key; 377 SMDB_DBENT *value; 378 SMDB_FLAG flags; 379 { 380 DBC *dbc = (DBC *) cursor->smdbc_impl; 381 382 return db2_error_to_smdb(dbc->c_put(dbc, &key->db, &value->db, 0)); 383 } 384 385 int 386 smdb2_cursor(database, cursor, flags) 387 SMDB_DATABASE *database; 388 SMDB_CURSOR **cursor; 389 SMDB_FLAG flags; 390 { 391 int result; 392 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db; 393 DBC *db2_cursor; 394 395 # if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 396 result = db->cursor(db, NULL, &db2_cursor, 0); 397 # else /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */ 398 result = db->cursor(db, NULL, &db2_cursor); 399 # endif /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */ 400 if (result != 0) 401 return db2_error_to_smdb(result); 402 403 *cursor = (SMDB_CURSOR *) malloc(sizeof(SMDB_CURSOR)); 404 if (*cursor == NULL) 405 return SMDBE_MALLOC; 406 407 (*cursor)->smdbc_close = smdb2_cursor_close; 408 (*cursor)->smdbc_del = smdb2_cursor_del; 409 (*cursor)->smdbc_get = smdb2_cursor_get; 410 (*cursor)->smdbc_put = smdb2_cursor_put; 411 (*cursor)->smdbc_impl = db2_cursor; 412 413 return SMDBE_OK; 414 } 415 416 # if DB_VERSION_MAJOR == 2 417 static int 418 smdb_db_open_internal(db_name, db_type, db_flags, db_params, db) 419 char *db_name; 420 DBTYPE db_type; 421 int db_flags; 422 SMDB_DBPARAMS *db_params; 423 DB **db; 424 { 425 void *params; 426 DB_INFO db_info; 427 428 params = NULL; 429 memset(&db_info, '\0', sizeof db_info); 430 if (db_params != NULL) 431 { 432 db_info.db_cachesize = db_params->smdbp_cache_size; 433 if (db_type == DB_HASH) 434 db_info.h_nelem = db_params->smdbp_num_elements; 435 if (db_params->smdbp_allow_dup) 436 db_info.flags |= DB_DUP; 437 params = &db_info; 438 } 439 return db_open(db_name, db_type, db_flags, 0644, NULL, params, db); 440 } 441 # endif /* DB_VERSION_MAJOR == 2 */ 442 443 # if DB_VERSION_MAJOR > 2 444 static int 445 smdb_db_open_internal(db_name, db_type, db_flags, db_params, db) 446 char *db_name; 447 DBTYPE db_type; 448 int db_flags; 449 SMDB_DBPARAMS *db_params; 450 DB **db; 451 { 452 int result; 453 454 result = db_create(db, NULL, 0); 455 if (result != 0 || *db == NULL) 456 return result; 457 458 if (db_params != NULL) 459 { 460 result = (*db)->set_cachesize(*db, 0, 461 db_params->smdbp_cache_size, 0); 462 if (result != 0) 463 { 464 (void) (*db)->close((*db), 0); 465 *db = NULL; 466 return db2_error_to_smdb(result); 467 } 468 if (db_type == DB_HASH) 469 { 470 result = (*db)->set_h_nelem(*db, db_params->smdbp_num_elements); 471 if (result != 0) 472 { 473 (void) (*db)->close(*db, 0); 474 *db = NULL; 475 return db2_error_to_smdb(result); 476 } 477 } 478 if (db_params->smdbp_allow_dup) 479 { 480 result = (*db)->set_flags(*db, DB_DUP); 481 if (result != 0) 482 { 483 (void) (*db)->close(*db, 0); 484 *db = NULL; 485 return db2_error_to_smdb(result); 486 } 487 } 488 } 489 490 result = (*db)->open(*db, db_name, NULL, db_type, db_flags, 0644); 491 if (result != 0) 492 { 493 (void) (*db)->close(*db, 0); 494 *db = NULL; 495 } 496 return db2_error_to_smdb(result); 497 } 498 # endif /* DB_VERSION_MAJOR > 2 */ 499 /* 500 ** SMDB_DB_OPEN -- Opens a db database. 501 ** 502 ** Parameters: 503 ** database -- An unallocated database pointer to a pointer. 504 ** db_name -- The name of the database without extension. 505 ** mode -- File permisions for a created database. 506 ** mode_mask -- Mode bits that must match on an opened database. 507 ** sff -- Flags for safefile. 508 ** type -- The type of database to open 509 ** See smdb_type_to_db2_type for valid types. 510 ** user_info -- User information for file permissions. 511 ** db_params -- 512 ** An SMDB_DBPARAMS struct including params. These 513 ** are processed according to the type of the 514 ** database. Currently supported params (only for 515 ** HASH type) are: 516 ** num_elements 517 ** cache_size 518 ** 519 ** Returns: 520 ** SMDBE_OK -- Success, other errno: 521 ** SMDBE_MALLOC -- Cannot allocate memory. 522 ** SMDBE_BAD_OPEN -- db_open didn't return an error, but 523 ** somehow the DB pointer is NULL. 524 ** Anything else: translated error from db2 525 */ 526 527 int 528 smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info, db_params) 529 SMDB_DATABASE **database; 530 char *db_name; 531 int mode; 532 int mode_mask; 533 long sff; 534 SMDB_DBTYPE type; 535 SMDB_USER_INFO *user_info; 536 SMDB_DBPARAMS *db_params; 537 { 538 bool lockcreated = FALSE; 539 int result; 540 int db_flags; 541 int lock_fd; 542 int db_fd; 543 SMDB_DATABASE *smdb_db; 544 SMDB_DB2_DATABASE *db2; 545 DB *db; 546 DBTYPE db_type; 547 struct stat stat_info; 548 char db_file_name[SMDB_MAX_NAME_LEN]; 549 550 *database = NULL; 551 552 result = smdb_add_extension(db_file_name, SMDB_MAX_NAME_LEN, 553 db_name, SMDB2_FILE_EXTENSION); 554 if (result != SMDBE_OK) 555 return result; 556 557 result = smdb_setup_file(db_name, SMDB2_FILE_EXTENSION, 558 mode_mask, sff, user_info, &stat_info); 559 if (result != SMDBE_OK) 560 return result; 561 562 lock_fd = -1; 563 564 if (stat_info.st_mode == ST_MODE_NOFILE && 565 bitset(mode, O_CREAT)) 566 lockcreated = TRUE; 567 568 result = smdb_lock_file(&lock_fd, db_name, mode, sff, 569 SMDB2_FILE_EXTENSION); 570 if (result != SMDBE_OK) 571 return result; 572 573 if (lockcreated) 574 { 575 mode |= O_TRUNC; 576 mode &= ~(O_CREAT|O_EXCL); 577 } 578 579 smdb_db = smdb_malloc_database(); 580 if (smdb_db == NULL) 581 return SMDBE_MALLOC; 582 583 db2 = smdb2_malloc_database(); 584 if (db2 == NULL) 585 return SMDBE_MALLOC; 586 587 db2->smdb2_lock_fd = lock_fd; 588 589 db_type = smdb_type_to_db2_type(type); 590 591 db = NULL; 592 593 db_flags = 0; 594 if (bitset(O_CREAT, mode)) 595 db_flags |= DB_CREATE; 596 if (bitset(O_TRUNC, mode)) 597 db_flags |= DB_TRUNCATE; 598 if (mode == O_RDONLY) 599 db_flags |= DB_RDONLY; 600 # if !HASFLOCK && defined(DB_FCNTL_LOCKING) 601 db_flags |= DB_FCNTL_LOCKING; 602 # endif /* !HASFLOCK && defined(DB_FCNTL_LOCKING) */ 603 604 result = smdb_db_open_internal(db_file_name, db_type, 605 db_flags, db_params, &db); 606 607 if (result == 0 && db != NULL) 608 { 609 result = db->fd(db, &db_fd); 610 if (result == 0) 611 result = SMDBE_OK; 612 } 613 else 614 { 615 /* Try and narrow down on the problem */ 616 if (result != 0) 617 result = db2_error_to_smdb(result); 618 else 619 result = SMDBE_BAD_OPEN; 620 } 621 622 if (result == SMDBE_OK) 623 result = smdb_filechanged(db_name, SMDB2_FILE_EXTENSION, db_fd, 624 &stat_info); 625 626 if (result == SMDBE_OK) 627 { 628 /* Everything is ok. Setup driver */ 629 db2->smdb2_db = db; 630 631 smdb_db->smdb_close = smdb2_close; 632 smdb_db->smdb_del = smdb2_del; 633 smdb_db->smdb_fd = smdb2_fd; 634 smdb_db->smdb_lockfd = smdb2_lockfd; 635 smdb_db->smdb_get = smdb2_get; 636 smdb_db->smdb_put = smdb2_put; 637 smdb_db->smdb_set_owner = smdb2_set_owner; 638 smdb_db->smdb_sync = smdb2_sync; 639 smdb_db->smdb_cursor = smdb2_cursor; 640 smdb_db->smdb_impl = db2; 641 642 *database = smdb_db; 643 644 return SMDBE_OK; 645 } 646 647 if (db != NULL) 648 db->close(db, 0); 649 650 smdb_unlock_file(db2->smdb2_lock_fd); 651 free(db2); 652 smdb_free_database(smdb_db); 653 654 return result; 655 } 656 657 #endif /* (DB_VERSION_MAJOR >= 2) */ 658