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