kdb.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <stdint.h>
  4. #include <string.h>
  5. #include <assert.h>
  6. #include <dlfcn.h>
  7. #include <faux/str.h>
  8. #include <faux/ini.h>
  9. #include <klish/khelper.h>
  10. #include <klish/kscheme.h>
  11. #include <klish/kdb.h>
  12. struct kdb_s {
  13. char *name; // Arbitrary name (can be used to generate SO file name)
  14. char *file; // SO file name
  15. faux_ini_t *ini;
  16. uint8_t major;
  17. uint8_t minor;
  18. void *dlhan; // dlopen() handler
  19. kdb_init_fn init_fn;
  20. kdb_fini_fn fini_fn;
  21. kdb_load_fn load_fn;
  22. kdb_load_fn deploy_fn;
  23. void *udata; // User data
  24. };
  25. // Simple methods
  26. // Name
  27. KGET_STR(db, name);
  28. // Shared object file
  29. KGET_STR(db, file);
  30. // INI
  31. KGET(db, faux_ini_t *, ini);
  32. KSET(db, faux_ini_t *, ini);
  33. // Version major number
  34. KGET(db, uint8_t, major);
  35. static KSET(db, uint8_t, major);
  36. // Version minor number
  37. KGET(db, uint8_t, minor);
  38. static KSET(db, uint8_t, minor);
  39. // User data
  40. KGET(db, void *, udata);
  41. KSET(db, void *, udata);
  42. kdb_t *kdb_new(const char *name, const char *file)
  43. {
  44. kdb_t *db = NULL;
  45. if (faux_str_is_empty(name))
  46. return NULL;
  47. db = faux_zmalloc(sizeof(*db));
  48. assert(db);
  49. if (!db)
  50. return NULL;
  51. // Initialize
  52. db->name = faux_str_dup(name);
  53. db->file = faux_str_dup(file);
  54. db->ini = NULL;
  55. db->major = 0;
  56. db->minor = 0;
  57. db->dlhan = NULL;
  58. db->init_fn = NULL;
  59. db->fini_fn = NULL;
  60. db->load_fn = NULL;
  61. db->deploy_fn = NULL;
  62. db->udata = NULL;
  63. return db;
  64. }
  65. void kdb_free(kdb_t *db)
  66. {
  67. if (!db)
  68. return;
  69. faux_str_free(db->name);
  70. faux_str_free(db->file);
  71. faux_ini_free(db->ini);
  72. if (db->dlhan)
  73. dlclose(db->dlhan);
  74. faux_free(db);
  75. }
  76. bool_t kdb_load_plugin(kdb_t *db)
  77. {
  78. const char *name = NULL;
  79. char *file_name = NULL;
  80. char *init_name = NULL;
  81. char *fini_name = NULL;
  82. char *load_name = NULL;
  83. char *deploy_name = NULL;
  84. char *major_name = NULL;
  85. char *minor_name = NULL;
  86. int flag = RTLD_NOW | RTLD_LOCAL;
  87. bool_t retcode = BOOL_FALSE;
  88. uint8_t *ver = NULL;
  89. assert(db);
  90. if (!db)
  91. return BOOL_FALSE;
  92. // Shared object file name
  93. name = kdb_name(db);
  94. if (kdb_file(db))
  95. file_name = faux_str_dup(kdb_file(db));
  96. else
  97. file_name = faux_str_sprintf(KDB_SONAME_FMT, name);
  98. // Symbol names
  99. major_name = faux_str_sprintf(KDB_MAJOR_FMT, name);
  100. minor_name = faux_str_sprintf(KDB_MINOR_FMT, name);
  101. init_name = faux_str_sprintf(KDB_INIT_FMT, name);
  102. fini_name = faux_str_sprintf(KDB_FINI_FMT, name);
  103. load_name = faux_str_sprintf(KDB_LOAD_FMT, name);
  104. deploy_name = faux_str_sprintf(KDB_DEPLOY_FMT, name);
  105. // Open shared object
  106. db->dlhan = dlopen(file_name, flag);
  107. if (!db->dlhan) {
  108. // fprintf(stderr, "Error: Can't open db \"%s\": %s\n",
  109. // this->name, dlerror());
  110. goto err;
  111. }
  112. // Get db version
  113. ver = (uint8_t *)dlsym(db->dlhan, major_name);
  114. if (!ver)
  115. goto err;
  116. kdb_set_major(db, *ver);
  117. ver = (uint8_t *)dlsym(db->dlhan, minor_name);
  118. if (!ver)
  119. goto err;
  120. kdb_set_minor(db, *ver);
  121. // Get db init function
  122. db->init_fn = dlsym(db->dlhan, init_name);
  123. db->fini_fn = dlsym(db->dlhan, fini_name);
  124. db->load_fn = dlsym(db->dlhan, load_name);
  125. db->deploy_fn = dlsym(db->dlhan, deploy_name);
  126. if (!db->load_fn && !db->deploy_fn) { // Strange DB plugin
  127. // fprintf(stderr, "Error: DB plugin \"%s\" has no deploy and load functions\n",
  128. // this->name);
  129. goto err;
  130. }
  131. retcode = BOOL_TRUE;
  132. err:
  133. faux_str_free(file_name);
  134. faux_str_free(major_name);
  135. faux_str_free(minor_name);
  136. faux_str_free(init_name);
  137. faux_str_free(fini_name);
  138. faux_str_free(load_name);
  139. faux_str_free(deploy_name);
  140. if (!retcode && db->dlhan)
  141. dlclose(db->dlhan);
  142. return retcode;
  143. }
  144. bool_t kdb_init(kdb_t *db)
  145. {
  146. assert(db);
  147. if (!db)
  148. return BOOL_FALSE;
  149. if (!db->init_fn)
  150. return BOOL_TRUE; // Init fn absence is not error
  151. return db->init_fn(db);
  152. }
  153. bool_t kdb_fini(kdb_t *db)
  154. {
  155. assert(db);
  156. if (!db)
  157. return BOOL_FALSE;
  158. if (!db->fini_fn)
  159. return BOOL_TRUE; // Fini fn absence is not error
  160. return db->fini_fn(db);
  161. }