1/* 2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. 4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5 * 6 * This software is available to you under a choice of one of two 7 * licenses. You may choose to be licensed under the terms of the GNU 8 * General Public License (GPL) Version 2, available from the file 9 * COPYING in the main directory of this source tree, or the 10 * OpenIB.org BSD license below: 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer. 19 * 20 * - Redistributions in binary form must reproduce the above 21 * copyright notice, this list of conditions and the following 22 * disclaimer in the documentation and/or other materials 23 * provided with the distribution. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * SOFTWARE. 33 * 34 */ 35 36/* 37 * Abstract: 38 * Implementation of the osm_db interface using simple text files 39 */ 40 41#if HAVE_CONFIG_H 42# include <config.h> 43#endif /* HAVE_CONFIG_H */ 44 45#include <sys/stat.h> 46#include <sys/types.h> 47#include <stdlib.h> 48#include <string.h> 49#include <opensm/st.h> 50#include <opensm/osm_db.h> 51 52/****d* Database/OSM_DB_MAX_LINE_LEN 53 * NAME 54 * OSM_DB_MAX_LINE_LEN 55 * 56 * DESCRIPTION 57 * The Maximal line length allowed for the file 58 * 59 * SYNOPSIS 60 */ 61#define OSM_DB_MAX_LINE_LEN 1024 62/**********/ 63 64/****d* Database/OSM_DB_MAX_GUID_LEN 65 * NAME 66 * OSM_DB_MAX_GUID_LEN 67 * 68 * DESCRIPTION 69 * The Maximal word length allowed for the file (guid or lid) 70 * 71 * SYNOPSIS 72 */ 73#define OSM_DB_MAX_GUID_LEN 32 74/**********/ 75 76/****s* OpenSM: Database/osm_db_domain_imp 77 * NAME 78 * osm_db_domain_imp 79 * 80 * DESCRIPTION 81 * An implementation for domain of the database based on text files and 82 * hash tables. 83 * 84 * SYNOPSIS 85 */ 86typedef struct osm_db_domain_imp { 87 char *file_name; 88 st_table *p_hash; 89 cl_spinlock_t lock; 90} osm_db_domain_imp_t; 91/* 92 * FIELDS 93 * 94 * SEE ALSO 95 * osm_db_domain_t 96 *********/ 97 98/****s* OpenSM: Database/osm_db_imp_t 99 * NAME 100 * osm_db_imp_t 101 * 102 * DESCRIPTION 103 * An implementation for file based database 104 * 105 * SYNOPSIS 106 */ 107typedef struct osm_db_imp { 108 char *db_dir_name; 109} osm_db_imp_t; 110/* 111 * FIELDS 112 * 113 * db_dir_name 114 * The directory holding the database 115 * 116 * SEE ALSO 117 * osm_db_t 118 *********/ 119 120/*************************************************************************** 121 ***************************************************************************/ 122void osm_db_construct(IN osm_db_t * const p_db) 123{ 124 memset(p_db, 0, sizeof(osm_db_t)); 125 cl_list_construct(&p_db->domains); 126} 127 128/*************************************************************************** 129 ***************************************************************************/ 130void osm_db_domain_destroy(IN osm_db_domain_t * const p_db_domain) 131{ 132 osm_db_domain_imp_t *p_domain_imp; 133 p_domain_imp = (osm_db_domain_imp_t *) p_db_domain->p_domain_imp; 134 135 osm_db_clear(p_db_domain); 136 137 cl_spinlock_destroy(&p_domain_imp->lock); 138 139 st_free_table(p_domain_imp->p_hash); 140 free(p_domain_imp->file_name); 141 free(p_domain_imp); 142} 143 144/*************************************************************************** 145 ***************************************************************************/ 146void osm_db_destroy(IN osm_db_t * const p_db) 147{ 148 osm_db_domain_t *p_domain; 149 150 while ((p_domain = cl_list_remove_head(&p_db->domains)) != NULL) { 151 osm_db_domain_destroy(p_domain); 152 free(p_domain); 153 } 154 cl_list_destroy(&p_db->domains); 155 free(p_db->p_db_imp); 156} 157 158/*************************************************************************** 159 ***************************************************************************/ 160int osm_db_init(IN osm_db_t * const p_db, IN osm_log_t * p_log) 161{ 162 osm_db_imp_t *p_db_imp; 163 struct stat dstat; 164 165 OSM_LOG_ENTER(p_log); 166 167 p_db_imp = (osm_db_imp_t *) malloc(sizeof(osm_db_imp_t)); 168 CL_ASSERT(p_db_imp != NULL); 169 170 p_db_imp->db_dir_name = getenv("OSM_CACHE_DIR"); 171 if (!p_db_imp->db_dir_name || !(*p_db_imp->db_dir_name)) 172 p_db_imp->db_dir_name = OSM_DEFAULT_CACHE_DIR; 173 174 /* Create the directory if it doesn't exist */ 175 /* There is a difference in creating directory between windows and linux */ 176#ifdef __WIN__ 177 /* Check if the directory exists. If not - create it. */ 178 CreateDirectory(p_db_imp->db_dir_name, NULL); 179#else /* __WIN__ */ 180 /* make sure the directory exists */ 181 if (lstat(p_db_imp->db_dir_name, &dstat)) { 182 if (mkdir(p_db_imp->db_dir_name, 0755)) { 183 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6101: " 184 "Failed to create the db directory:%s\n", 185 p_db_imp->db_dir_name); 186 OSM_LOG_EXIT(p_log); 187 return 1; 188 } 189 } 190#endif 191 192 p_db->p_log = p_log; 193 p_db->p_db_imp = (void *)p_db_imp; 194 195 cl_list_init(&p_db->domains, 5); 196 197 OSM_LOG_EXIT(p_log); 198 199 return 0; 200} 201 202/*************************************************************************** 203 ***************************************************************************/ 204osm_db_domain_t *osm_db_domain_init(IN osm_db_t * const p_db, 205 IN char *domain_name) 206{ 207 osm_db_domain_t *p_domain; 208 osm_db_domain_imp_t *p_domain_imp; 209 int dir_name_len; 210 osm_log_t *p_log = p_db->p_log; 211 FILE *p_file; 212 213 OSM_LOG_ENTER(p_log); 214 215 /* allocate a new domain object */ 216 p_domain = (osm_db_domain_t *) malloc(sizeof(osm_db_domain_t)); 217 CL_ASSERT(p_domain != NULL); 218 219 p_domain_imp = 220 (osm_db_domain_imp_t *) malloc(sizeof(osm_db_domain_imp_t)); 221 CL_ASSERT(p_domain_imp != NULL); 222 223 dir_name_len = strlen(((osm_db_imp_t *) p_db->p_db_imp)->db_dir_name); 224 225 /* set the domain file name */ 226 p_domain_imp->file_name = 227 (char *)malloc(sizeof(char) * (dir_name_len) + strlen(domain_name) + 228 2); 229 CL_ASSERT(p_domain_imp->file_name != NULL); 230 strcpy(p_domain_imp->file_name, 231 ((osm_db_imp_t *) p_db->p_db_imp)->db_dir_name); 232 strcat(p_domain_imp->file_name, domain_name); 233 234 /* make sure the file exists - or exit if not writable */ 235 p_file = fopen(p_domain_imp->file_name, "a+"); 236 if (!p_file) { 237 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6102: " 238 "Failed to open the db file:%s\n", 239 p_domain_imp->file_name); 240 free(p_domain_imp); 241 free(p_domain); 242 p_domain = NULL; 243 goto Exit; 244 } 245 fclose(p_file); 246 247 /* initialize the hash table object */ 248 p_domain_imp->p_hash = st_init_strtable(); 249 CL_ASSERT(p_domain_imp->p_hash != NULL); 250 251 p_domain->p_db = p_db; 252 cl_list_insert_tail(&p_db->domains, p_domain); 253 p_domain->p_domain_imp = p_domain_imp; 254 cl_spinlock_construct(&p_domain_imp->lock); 255 cl_spinlock_init(&p_domain_imp->lock); 256 257Exit: 258 OSM_LOG_EXIT(p_log); 259 return p_domain; 260} 261 262/*************************************************************************** 263 ***************************************************************************/ 264int osm_db_restore(IN osm_db_domain_t * p_domain) 265{ 266 267 osm_log_t *p_log = p_domain->p_db->p_log; 268 osm_db_domain_imp_t *p_domain_imp = 269 (osm_db_domain_imp_t *) p_domain->p_domain_imp; 270 FILE *p_file; 271 int status; 272 char sLine[OSM_DB_MAX_LINE_LEN]; 273 boolean_t before_key; 274 char *p_first_word, *p_rest_of_line, *p_last; 275 char *p_key = NULL; 276 char *p_prev_val, *p_accum_val = NULL; 277 char *endptr = NULL; 278 unsigned int line_num; 279 280 OSM_LOG_ENTER(p_log); 281 282 /* take the lock on the domain */ 283 cl_spinlock_acquire(&p_domain_imp->lock); 284 285 /* open the file - read mode */ 286 p_file = fopen(p_domain_imp->file_name, "r"); 287 288 if (!p_file) { 289 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6103: " 290 "Failed to open the db file:%s\n", 291 p_domain_imp->file_name); 292 status = 1; 293 goto Exit; 294 } 295 296 /* parse the file allocating new hash tables as required */ 297 /* 298 states: 299 before_key (0) -> in_key (1) 300 301 before_key: if a word on the first byte - it is the key. state=in_key 302 the rest of the line is start of the value. 303 in_key: unless the line is empty - add it (with newlines) to the value. 304 if empty: state=before_key 305 */ 306 status = 0; 307 before_key = TRUE; 308 line_num = 0; 309 /* if we got to EOF in the middle of a key we add a last newline */ 310 while ((fgets(sLine, OSM_DB_MAX_LINE_LEN, p_file) != NULL) || 311 ((before_key == FALSE) && strcpy(sLine, "\n")) 312 ) { 313 line_num++; 314 if (before_key) { 315 if ((sLine[0] != ' ') && (sLine[0] != '\t') 316 && (sLine[0] != '\n')) { 317 /* we got a new key */ 318 before_key = FALSE; 319 320 /* handle the key */ 321 p_first_word = 322 strtok_r(sLine, " \t\n", &p_last); 323 if (!p_first_word) { 324 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6104: " 325 "Failed to get key from line:%u : %s (file:%s)\n", 326 line_num, sLine, 327 p_domain_imp->file_name); 328 status = 1; 329 goto EndParsing; 330 } 331 if (strlen(p_first_word) > OSM_DB_MAX_GUID_LEN) { 332 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 610A: " 333 "Illegal key from line:%u : %s (file:%s)\n", 334 line_num, sLine, 335 p_domain_imp->file_name); 336 status = 1; 337 goto EndParsing; 338 } 339 340 p_key = 341 (char *)malloc(sizeof(char) * 342 (strlen(p_first_word) + 1)); 343 strcpy(p_key, p_first_word); 344 345 p_rest_of_line = strtok_r(NULL, "\n", &p_last); 346 if (p_rest_of_line != NULL) { 347 p_accum_val = 348 (char *)malloc(sizeof(char) * 349 (strlen 350 (p_rest_of_line) + 351 1)); 352 strcpy(p_accum_val, p_rest_of_line); 353 } else { 354 p_accum_val = (char *)malloc(2); 355 strcpy(p_accum_val, "\0"); 356 } 357 } else if (sLine[0] != '\n') { 358 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6105: " 359 "How did we get here? line:%u : %s (file:%s)\n", 360 line_num, sLine, 361 p_domain_imp->file_name); 362 status = 1; 363 goto EndParsing; 364 } 365 } /* before key */ 366 else { 367 /* we already have a key */ 368 369 if (sLine[0] == '\n') { 370 /* got an end of key */ 371 before_key = TRUE; 372 373 /* make sure the key was not previously used */ 374 if (st_lookup(p_domain_imp->p_hash, 375 (st_data_t) p_key, 376 (void *) & p_prev_val)) { 377 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6106: " 378 "Key:%s already exists in:%s with value:%s." 379 " Removing it\n", 380 p_key, 381 p_domain_imp->file_name, 382 p_prev_val); 383 } else { 384 p_prev_val = NULL; 385 } 386 387 OSM_LOG(p_log, OSM_LOG_DEBUG, 388 "Got key:%s value:%s\n", p_key, 389 p_accum_val); 390 391 /* check that the key is a number */ 392 if (!strtouq(p_key, &endptr, 0) 393 && *endptr != '\0') { 394 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 610B: " 395 "Key:%s is invalid\n", p_key); 396 } else { 397 /* store our key and value */ 398 st_insert(p_domain_imp->p_hash, 399 (st_data_t) p_key, 400 (st_data_t) p_accum_val); 401 } 402 } else { 403 /* accumulate into the value */ 404 p_prev_val = p_accum_val; 405 p_accum_val = 406 (char *)malloc(strlen(p_prev_val) + 407 strlen(sLine) + 1); 408 strcpy(p_accum_val, p_prev_val); 409 free(p_prev_val); 410 strcat(p_accum_val, sLine); 411 } 412 } /* in key */ 413 } /* while lines or last line */ 414 415EndParsing: 416 fclose(p_file); 417 418Exit: 419 cl_spinlock_release(&p_domain_imp->lock); 420 OSM_LOG_EXIT(p_log); 421 return status; 422} 423 424/*************************************************************************** 425 ***************************************************************************/ 426static int __osm_dump_tbl_entry(st_data_t key, st_data_t val, st_data_t arg) 427{ 428 FILE *p_file = (FILE *) arg; 429 char *p_key = (char *)key; 430 char *p_val = (char *)val; 431 432 fprintf(p_file, "%s %s\n\n", p_key, p_val); 433 return ST_CONTINUE; 434} 435 436int osm_db_store(IN osm_db_domain_t * p_domain) 437{ 438 osm_log_t *p_log = p_domain->p_db->p_log; 439 osm_db_domain_imp_t *p_domain_imp; 440 FILE *p_file; 441 int status = 0; 442 char *p_tmp_file_name; 443 444 OSM_LOG_ENTER(p_log); 445 446 p_domain_imp = (osm_db_domain_imp_t *) p_domain->p_domain_imp; 447 p_tmp_file_name = 448 (char *)malloc(sizeof(char) * 449 (strlen(p_domain_imp->file_name) + 8)); 450 strcpy(p_tmp_file_name, p_domain_imp->file_name); 451 strcat(p_tmp_file_name, ".tmp"); 452 453 cl_spinlock_acquire(&p_domain_imp->lock); 454 455 /* open up the output file */ 456 p_file = fopen(p_tmp_file_name, "w"); 457 if (!p_file) { 458 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6107: " 459 "Failed to open the db file:%s for writing\n", 460 p_domain_imp->file_name); 461 status = 1; 462 goto Exit; 463 } 464 465 st_foreach(p_domain_imp->p_hash, __osm_dump_tbl_entry, 466 (st_data_t) p_file); 467 fclose(p_file); 468 469 /* move the domain file */ 470 status = remove(p_domain_imp->file_name); 471 if (status) { 472 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6109: " 473 "Failed to remove file:%s (err:%u)\n", 474 p_domain_imp->file_name, status); 475 } 476 477 status = rename(p_tmp_file_name, p_domain_imp->file_name); 478 if (status) { 479 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6108: " 480 "Failed to rename the db file to:%s (err:%u)\n", 481 p_domain_imp->file_name, status); 482 } 483Exit: 484 cl_spinlock_release(&p_domain_imp->lock); 485 free(p_tmp_file_name); 486 OSM_LOG_EXIT(p_log); 487 return status; 488} 489 490/*************************************************************************** 491 ***************************************************************************/ 492/* simply de-allocate the key and the value and return the code 493 that makes the st_foreach delete the entry */ 494static int __osm_clear_tbl_entry(st_data_t key, st_data_t val, st_data_t arg) 495{ 496 free((char *)key); 497 free((char *)val); 498 return ST_DELETE; 499} 500 501int osm_db_clear(IN osm_db_domain_t * p_domain) 502{ 503 osm_db_domain_imp_t *p_domain_imp = 504 (osm_db_domain_imp_t *) p_domain->p_domain_imp; 505 506 cl_spinlock_acquire(&p_domain_imp->lock); 507 st_foreach(p_domain_imp->p_hash, __osm_clear_tbl_entry, 508 (st_data_t) NULL); 509 cl_spinlock_release(&p_domain_imp->lock); 510 511 return 0; 512} 513 514/*************************************************************************** 515 ***************************************************************************/ 516static int __osm_get_key_of_tbl_entry(st_data_t key, st_data_t val, 517 st_data_t arg) 518{ 519 cl_list_t *p_list = (cl_list_t *) arg; 520 cl_list_insert_tail(p_list, (void *)key); 521 return ST_CONTINUE; 522} 523 524int osm_db_keys(IN osm_db_domain_t * p_domain, OUT cl_list_t * p_key_list) 525{ 526 osm_db_domain_imp_t *p_domain_imp = 527 (osm_db_domain_imp_t *) p_domain->p_domain_imp; 528 529 cl_spinlock_acquire(&p_domain_imp->lock); 530 531 st_foreach(p_domain_imp->p_hash, 532 __osm_get_key_of_tbl_entry, (st_data_t) p_key_list); 533 534 cl_spinlock_release(&p_domain_imp->lock); 535 536 return 0; 537} 538 539/*************************************************************************** 540 ***************************************************************************/ 541char *osm_db_lookup(IN osm_db_domain_t * p_domain, IN char *const p_key) 542{ 543 osm_db_domain_imp_t *p_domain_imp = 544 (osm_db_domain_imp_t *) p_domain->p_domain_imp; 545 char *p_val = NULL; 546 547 cl_spinlock_acquire(&p_domain_imp->lock); 548 549 if (!st_lookup 550 (p_domain_imp->p_hash, (st_data_t) p_key, (void *) & p_val)) 551 p_val = NULL; 552 553 cl_spinlock_release(&p_domain_imp->lock); 554 555 return p_val; 556} 557 558/*************************************************************************** 559 ***************************************************************************/ 560int 561osm_db_update(IN osm_db_domain_t * p_domain, 562 IN char *const p_key, IN char *const p_val) 563{ 564 osm_log_t *p_log = p_domain->p_db->p_log; 565 osm_db_domain_imp_t *p_domain_imp = 566 (osm_db_domain_imp_t *) p_domain->p_domain_imp; 567 char *p_prev_val = NULL; 568 char *p_new_key; 569 char *p_new_val; 570 571 cl_spinlock_acquire(&p_domain_imp->lock); 572 573 if (st_lookup(p_domain_imp->p_hash, 574 (st_data_t) p_key, (void *) & p_prev_val)) { 575 OSM_LOG(p_log, OSM_LOG_DEBUG, 576 "Key:%s previously exists in:%s with value:%s\n", 577 p_key, p_domain_imp->file_name, p_prev_val); 578 p_new_key = p_key; 579 } else { 580 /* need to allocate the key */ 581 p_new_key = malloc(sizeof(char) * (strlen(p_key) + 1)); 582 strcpy(p_new_key, p_key); 583 } 584 585 /* need to arange a new copy of the value */ 586 p_new_val = malloc(sizeof(char) * (strlen(p_val) + 1)); 587 strcpy(p_new_val, p_val); 588 589 st_insert(p_domain_imp->p_hash, (st_data_t) p_new_key, 590 (st_data_t) p_new_val); 591 592 if (p_prev_val) 593 free(p_prev_val); 594 595 cl_spinlock_release(&p_domain_imp->lock); 596 597 return 0; 598} 599 600/*************************************************************************** 601 ***************************************************************************/ 602int osm_db_delete(IN osm_db_domain_t * p_domain, IN char *const p_key) 603{ 604 osm_log_t *p_log = p_domain->p_db->p_log; 605 osm_db_domain_imp_t *p_domain_imp = 606 (osm_db_domain_imp_t *) p_domain->p_domain_imp; 607 char *p_prev_val = NULL; 608 int res; 609 610 OSM_LOG_ENTER(p_log); 611 612 cl_spinlock_acquire(&p_domain_imp->lock); 613 if (st_delete(p_domain_imp->p_hash, 614 (void *) & p_key, (void *) & p_prev_val)) { 615 if (st_lookup(p_domain_imp->p_hash, 616 (st_data_t) p_key, (void *) & p_prev_val)) { 617 OSM_LOG(p_log, OSM_LOG_ERROR, 618 "key:%s still exists in:%s with value:%s\n", 619 p_key, p_domain_imp->file_name, p_prev_val); 620 res = 1; 621 } else { 622 free(p_key); 623 free(p_prev_val); 624 res = 0; 625 } 626 } else { 627 OSM_LOG(p_log, OSM_LOG_DEBUG, 628 "fail to find key:%s. delete failed\n", p_key); 629 res = 1; 630 } 631 cl_spinlock_release(&p_domain_imp->lock); 632 633 OSM_LOG_EXIT(p_log); 634 return res; 635} 636 637#ifdef TEST_OSMDB 638#include <stdlib.h> 639#include <math.h> 640 641int main(int argc, char **argv) 642{ 643 osm_db_t db; 644 osm_log_t log; 645 osm_db_domain_t *p_dbd; 646 cl_list_t keys; 647 cl_list_iterator_t kI; 648 char *p_key; 649 char *p_val; 650 int i; 651 652 cl_list_construct(&keys); 653 cl_list_init(&keys, 10); 654 655 osm_log_init_v2(&log, TRUE, 0xff, "/var/log/osm_db_test.log", 0, FALSE); 656 657 osm_db_construct(&db); 658 if (osm_db_init(&db, &log)) { 659 printf("db init failed\n"); 660 exit(1); 661 } 662 663 p_dbd = osm_db_domain_init(&db, "lid_by_guid"); 664 665 if (osm_db_restore(p_dbd)) { 666 printf("failed to restore\n"); 667 } 668 669 if (osm_db_keys(p_dbd, &keys)) { 670 printf("failed to get keys\n"); 671 } else { 672 kI = cl_list_head(&keys); 673 while (kI != cl_list_end(&keys)) { 674 p_key = cl_list_obj(kI); 675 kI = cl_list_next(kI); 676 677 p_val = osm_db_lookup(p_dbd, p_key); 678 printf("key = %s val = %s\n", p_key, p_val); 679 } 680 } 681 682 cl_list_remove_all(&keys); 683 684 /* randomly add and remove numbers */ 685 for (i = 0; i < 10; i++) { 686 int k; 687 float v; 688 int is_add; 689 char val_buf[16]; 690 char key_buf[16]; 691 692 k = floor(1.0 * rand() / RAND_MAX * 100); 693 v = rand(); 694 sprintf(key_buf, "%u", k); 695 sprintf(val_buf, "%u", v); 696 697 is_add = (rand() < RAND_MAX / 2); 698 699 if (is_add) { 700 osm_db_update(p_dbd, key_buf, val_buf); 701 } else { 702 osm_db_delete(p_dbd, key_buf); 703 } 704 } 705 if (osm_db_keys(p_dbd, &keys)) { 706 printf("failed to get keys\n"); 707 } else { 708 kI = cl_list_head(&keys); 709 while (kI != cl_list_end(&keys)) { 710 p_key = cl_list_obj(kI); 711 kI = cl_list_next(kI); 712 713 p_val = osm_db_lookup(p_dbd, p_key); 714 printf("key = %s val = %s\n", p_key, p_val); 715 } 716 } 717 if (osm_db_store(p_dbd)) 718 printf("failed to store\n"); 719 720 osm_db_destroy(&db); 721 cl_list_destroy(&keys); 722} 723#endif 724