kv_linux.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. #include <sys/stat.h>
  6. #include <sys/types.h>
  7. #include <unistd.h>
  8. #include <dirent.h>
  9. #include <ulog/ulog.h>
  10. #include "kv_linux.h"
  11. #define TAG "kvlinux"
  12. static int char2hex(char c, uint8_t *x)
  13. {
  14. if (c >= '0' && c <= '9') {
  15. *x = c - '0';
  16. } else if (c >= 'a' && c <= 'f') {
  17. *x = c - 'a' + 10;
  18. } else if (c >= 'A' && c <= 'F') {
  19. *x = c - 'A' + 10;
  20. } else {
  21. return -EINVAL;
  22. }
  23. return 0;
  24. }
  25. static int hex2char(uint8_t x, char *c)
  26. {
  27. if (x <= 9) {
  28. *c = x + '0';
  29. } else if (x >= 10 && x <= 15) {
  30. *c = x - 10 + 'a';
  31. } else {
  32. return -EINVAL;
  33. }
  34. return 0;
  35. }
  36. static size_t bin2hex(const uint8_t *buf, size_t buflen, char *hex, size_t hexlen)
  37. {
  38. if ((hexlen + 1) < buflen * 2) {
  39. return 0;
  40. }
  41. for (size_t i = 0; i < buflen; i++) {
  42. if (hex2char(buf[i] >> 4, &hex[2 * i]) < 0) {
  43. return 0;
  44. }
  45. if (hex2char(buf[i] & 0xf, &hex[2 * i + 1]) < 0) {
  46. return 0;
  47. }
  48. }
  49. hex[2 * buflen] = '\0';
  50. return 2 * buflen;
  51. }
  52. static size_t hex2bin(const char *hex, size_t hexlen, uint8_t *buf, size_t buflen)
  53. {
  54. uint8_t dec;
  55. if (buflen < hexlen / 2 + hexlen % 2) {
  56. return 0;
  57. }
  58. /* if hexlen is uneven, insert leading zero nibble */
  59. if (hexlen % 2) {
  60. if (char2hex(hex[0], &dec) < 0) {
  61. return 0;
  62. }
  63. buf[0] = dec;
  64. hex++;
  65. buf++;
  66. }
  67. /* regular hex conversion */
  68. for (size_t i = 0; i < hexlen / 2; i++) {
  69. if (char2hex(hex[2 * i], &dec) < 0) {
  70. return 0;
  71. }
  72. buf[i] = dec << 4;
  73. if (char2hex(hex[2 * i + 1], &dec) < 0) {
  74. return 0;
  75. }
  76. buf[i] += dec;
  77. }
  78. return hexlen / 2 + hexlen % 2;
  79. }
  80. static int mkdirpath(const char *path)
  81. {
  82. int ret;
  83. char str[KV_MAX_KEYPATH_LEN];
  84. int need_exit;
  85. if (path[0] != '/') {
  86. return -1;
  87. }
  88. char *ch = strchr(path, '/');
  89. need_exit = 0;
  90. while (ch && !need_exit) {
  91. ch = strchr(ch + 1, '/');
  92. if (ch == NULL) {
  93. if (path[strlen(path) - 1] == '/') {
  94. break;
  95. }
  96. ch = (char *)path + strlen(path);
  97. need_exit = 1;
  98. }
  99. snprintf(str, ch - path + 1, "%s", path);
  100. if (access(str, 0) != 0) {
  101. ret = mkdir(str, 0644);
  102. LOGD(TAG, "mkdir %s ret=%s", str, strerror(ret));
  103. }
  104. }
  105. return 0;
  106. }
  107. static int rmdirpath(const char *path)
  108. {
  109. DIR * dir;
  110. struct dirent *ptr;
  111. if ((dir = opendir(path)) == NULL) {
  112. LOGE(TAG, "%s: opendir error,%s", __FUNCTION__, strerror(errno));
  113. return -1;
  114. }
  115. while ((ptr = readdir(dir)) != NULL) {
  116. if (strcmp(ptr->d_name, ".") == 0 ||
  117. strcmp(ptr->d_name, "..") == 0) ///current dir OR parrent dir
  118. continue;
  119. else if (ptr->d_type == DT_REG) {
  120. char *hexkey = ptr->d_name;
  121. char key[KV_MAX_KEY_LEN * 2];
  122. size_t ret = hex2bin(hexkey, strlen(hexkey), (uint8_t *)key, sizeof(key));
  123. key[ret] = '\0';
  124. LOGD(TAG, "%s: remove key %s", __FUNCTION__, key);
  125. char keypath[KV_MAX_KEYPATH_LEN];
  126. snprintf(keypath, sizeof(keypath), "%s/%s", path, hexkey);
  127. remove(keypath);
  128. } else if (ptr->d_type == DT_DIR) {
  129. LOGW(TAG, "%s: dir(%s) in kv path", __FUNCTION__, ptr->d_name);
  130. } else {
  131. LOGW(TAG, "%s: unvalid file(%s) type(%d) in kv path", __FUNCTION__, ptr->d_name,
  132. ptr->d_type);
  133. }
  134. }
  135. closedir(dir);
  136. return 0;
  137. }
  138. int kv_init(kv_t *kv, const char *path)
  139. {
  140. if (kv == NULL) {
  141. LOGE(TAG, "%s: param error, path=%p", __FUNCTION__, path);
  142. return -1;
  143. }
  144. /* like mkdir -p */
  145. mkdirpath(path);
  146. /* copy path to kv obj */
  147. snprintf(kv->path, sizeof(kv->path), "%s", path);
  148. /* just seem as yoc */
  149. kv->handle = 1;
  150. return 0;
  151. }
  152. int kv_reset(kv_t *kv)
  153. {
  154. if (kv == NULL) {
  155. LOGE(TAG, "%s: param error", __FUNCTION__);
  156. return -1;
  157. }
  158. rmdirpath(kv->path);
  159. return 0;
  160. }
  161. int kv_set(kv_t *kv, const char *key, void *value, int size)
  162. {
  163. FILE *fd = NULL;
  164. if (kv == NULL || value == NULL || size == 0) {
  165. LOGE(TAG, "%s: param error, kv=%p value=%p size=%d", __FUNCTION__, key, value, size);
  166. return -1;
  167. }
  168. char hexkey[KV_MAX_KEY_LEN * 2];
  169. bin2hex((uint8_t *)key, strlen(key), hexkey, sizeof(hexkey));
  170. char keypath[KV_MAX_KEYPATH_LEN];
  171. snprintf(keypath, sizeof(keypath), "%s/%s", kv->path, hexkey);
  172. fd = fopen(keypath, "w");
  173. if (fd == NULL) {
  174. LOGE(TAG, "open %s file error %s", key, strerror(errno));
  175. return -1;
  176. }
  177. size_t wlen = fwrite(value, 1, size, fd);
  178. if (wlen != size) {
  179. LOGE(TAG, "write size error, write size=%d ret=%d", size, wlen);
  180. fclose(fd);
  181. return -1;
  182. }
  183. fflush(fd);
  184. fsync(fileno(fd));
  185. fclose(fd);
  186. return wlen;
  187. }
  188. int kv_get(kv_t *kv, const char *key, void *value, int size)
  189. {
  190. FILE *fd = NULL;
  191. if (kv == NULL || value == NULL || size == 0) {
  192. LOGE(TAG, "%s: param error, kv=%p value=%p size=%d", __FUNCTION__, key, value, size);
  193. return -1;
  194. }
  195. char hexkey[KV_MAX_KEY_LEN * 2];
  196. bin2hex((uint8_t *)key, strlen(key), hexkey, sizeof(hexkey));
  197. char keypath[KV_MAX_KEYPATH_LEN];
  198. snprintf(keypath, sizeof(keypath), "%s/%s", kv->path, hexkey);
  199. fd = fopen(keypath, "rb");
  200. if (fd == NULL) {
  201. //LOGE(TAG, "open %s file error %s", key, strerror(errno));
  202. return -1;
  203. }
  204. size_t rlen = fread(value, 1, size, fd);
  205. fclose(fd);
  206. return rlen;
  207. }
  208. int kv_rm(kv_t *kv, const char *key)
  209. {
  210. if (kv == NULL || key == NULL) {
  211. LOGE(TAG, "%s: param error, kv=%p key=%p", __FUNCTION__, kv, key);
  212. return -1;
  213. }
  214. char hexkey[KV_MAX_KEY_LEN * 2];
  215. bin2hex((uint8_t *)key, strlen(key), hexkey, sizeof(hexkey));
  216. char keypath[KV_MAX_KEYPATH_LEN];
  217. snprintf(keypath, sizeof(keypath), "%s/%s", kv->path, hexkey);
  218. /* remove key */
  219. int ret = remove(keypath);
  220. if (ret < 0) {
  221. LOGE(TAG, "%s: remove key error, key=%s ret=%d", __FUNCTION__, keypath, ret);
  222. }
  223. return ret;
  224. }
  225. void kv_iter(kv_t *kv, void (*func)(char *key, char *val, uint16_t val_size, void *arg), void *arg)
  226. {
  227. DIR * dir;
  228. struct dirent *ptr;
  229. if (kv == NULL || func == NULL) {
  230. LOGE(TAG, "%s: param error", __FUNCTION__);
  231. return;
  232. }
  233. if ((dir = opendir(kv->path)) == NULL) {
  234. LOGE(TAG, "%s: opendir error,%s", __FUNCTION__, strerror(errno));
  235. return;
  236. }
  237. while ((ptr = readdir(dir)) != NULL) {
  238. if (strcmp(ptr->d_name, ".") == 0 ||
  239. strcmp(ptr->d_name, "..") == 0) ///current dir OR parrent dir
  240. continue;
  241. else if (ptr->d_type == DT_REG) {
  242. void *value = malloc(KV_MAX_VALUE_LEN);
  243. char *hexkey = ptr->d_name;
  244. char key[KV_MAX_KEY_LEN * 2];
  245. size_t ret = hex2bin(hexkey, strlen(hexkey), (uint8_t *)key, sizeof(key));
  246. key[ret] = '\0';
  247. //LOGD(TAG, "%s: iter key %s", __FUNCTION__, key);
  248. int rlen = kv_get(kv, key, value, KV_MAX_VALUE_LEN);
  249. func(key, value, rlen, arg);
  250. free(value);
  251. } else if (ptr->d_type == DT_DIR) {
  252. LOGW(TAG, "%s: dir(%s) in kv path", __FUNCTION__, ptr->d_name);
  253. } else {
  254. LOGW(TAG, "%s: unvalid file(%s) type(%d) in kv path", __FUNCTION__, ptr->d_name,
  255. ptr->d_type);
  256. }
  257. }
  258. closedir(dir);
  259. }
  260. /********************************
  261. * MUTEX
  262. ********************************/
  263. #include <sys/ipc.h>
  264. #include <sys/shm.h>
  265. typedef struct {
  266. pthread_mutex_t lock;
  267. int ready;
  268. } pthread_mutex_shm_t;
  269. int aos_kv_mutex_new(aos_kv_mutex_t *mutex)
  270. {
  271. /* generate share mm keyid */
  272. key_t shmkey = ftok(mutex->key_file, 0);
  273. LOGD(TAG, "shmkey=0x%x file=%s", shmkey, mutex->key_file);
  274. if (shmkey < 0) {
  275. LOGE(TAG, "%s: shmkey error", __FUNCTION__);
  276. return -1;
  277. }
  278. /* create or get share mm by keyid */
  279. int shmid = shmget(shmkey, sizeof(pthread_mutex_shm_t), 0666 | IPC_CREAT);
  280. if (shmid < 0) {
  281. LOGE(TAG, "%s: shmget error", __FUNCTION__);
  282. return -1;
  283. }
  284. /* get share mm addr by shmid */
  285. void *share_addr = shmat(shmid, (void *)0, 0);
  286. if (share_addr == NULL) {
  287. LOGE(TAG, "%s: shmat error", __FUNCTION__);
  288. shmctl(shmid, IPC_RMID, NULL);
  289. return -1;
  290. }
  291. /* shm stat check, firt ref, clean buffer */
  292. struct shmid_ds shm_stat;
  293. if (shmctl(shmid, IPC_STAT, &shm_stat) < 0) {
  294. LOGE(TAG, "%s: shmctl get stat error", __FUNCTION__);
  295. return -1;
  296. }
  297. if (shm_stat.shm_nattch == 1) {
  298. LOGD(TAG, "first process init shm buffer");
  299. memset(share_addr, 0, sizeof(pthread_mutex_shm_t));
  300. }
  301. /* create share mutex */
  302. pthread_mutex_shm_t *shm_mutex = (pthread_mutex_shm_t *)share_addr;
  303. if (shm_mutex->ready != 0x05050505) {
  304. pthread_mutexattr_t mutex_attr;
  305. pthread_mutexattr_init(&mutex_attr);
  306. pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
  307. pthread_mutex_init(&shm_mutex->lock, &mutex_attr);
  308. shm_mutex->ready = 0x05050505;
  309. LOGD(TAG, "%s: create share mutex shmid=%d", __FUNCTION__, shmid);
  310. } else {
  311. LOGD(TAG, "%s: get share mutex shmid=%d", __FUNCTION__, shmid);
  312. }
  313. /* save handle */
  314. mutex->hdl = shm_mutex;
  315. return 0;
  316. }
  317. void aos_kv_mutex_free(aos_kv_mutex_t *mutex)
  318. {
  319. LOGE(TAG, "%s: no implement", __FUNCTION__);
  320. }
  321. int aos_kv_mutex_lock(aos_kv_mutex_t *mutex, unsigned int timeout)
  322. {
  323. if (mutex->hdl == NULL) {
  324. LOGI(TAG, "%s: mutex no hdl", __FUNCTION__);
  325. return -1;
  326. }
  327. pthread_mutex_shm_t *shm_mutex = (pthread_mutex_shm_t *)mutex->hdl;
  328. return pthread_mutex_lock(&shm_mutex->lock);
  329. }
  330. int aos_kv_mutex_unlock(aos_kv_mutex_t *mutex)
  331. {
  332. if (mutex->hdl == NULL) {
  333. LOGI(TAG, "%s: mutex no hdl", __FUNCTION__);
  334. return -1;
  335. }
  336. pthread_mutex_shm_t *shm_mutex = (pthread_mutex_shm_t *)mutex->hdl;
  337. return pthread_mutex_unlock(&shm_mutex->lock);
  338. }