1 /*
2 * Copyright (c) 2018 Nordic Semiconductor ASA
3 * Copyright (c) 2015 Runtime Inc
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <stdbool.h>
11 #include <errno.h>
12 #include <zephyr/kernel.h>
13
14 #include <zephyr/settings/settings.h>
15 #include "settings_priv.h"
16 #include <zephyr/types.h>
17 #include <zephyr/sys/iterable_sections.h>
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_REGISTER(settings, CONFIG_SETTINGS_LOG_LEVEL);
20
21 #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS)
22 sys_slist_t settings_handlers;
23 #endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */
24
25 K_MUTEX_DEFINE(settings_lock);
26
27
28 void settings_store_init(void);
29
settings_init(void)30 void settings_init(void)
31 {
32 #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS)
33 sys_slist_init(&settings_handlers);
34 #endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */
35 settings_store_init();
36 }
37
38 #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS)
settings_register(struct settings_handler * handler)39 int settings_register(struct settings_handler *handler)
40 {
41 int rc = 0;
42
43 STRUCT_SECTION_FOREACH(settings_handler_static, ch) {
44 if (strcmp(handler->name, ch->name) == 0) {
45 return -EEXIST;
46 }
47 }
48
49 k_mutex_lock(&settings_lock, K_FOREVER);
50
51 struct settings_handler *ch;
52 SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) {
53 if (strcmp(handler->name, ch->name) == 0) {
54 rc = -EEXIST;
55 goto end;
56 }
57 }
58 sys_slist_append(&settings_handlers, &handler->node);
59
60 end:
61 k_mutex_unlock(&settings_lock);
62 return rc;
63 }
64 #endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */
65
settings_name_steq(const char * name,const char * key,const char ** next)66 int settings_name_steq(const char *name, const char *key, const char **next)
67 {
68 if (next) {
69 *next = NULL;
70 }
71
72 if ((!name) || (!key)) {
73 return 0;
74 }
75
76 /* name might come from flash directly, in flash the name would end
77 * with '=' or '\0' depending how storage is done. Flash reading is
78 * limited to what can be read
79 */
80
81 while ((*key != '\0') && (*key == *name) &&
82 (*name != '\0') && (*name != SETTINGS_NAME_END)) {
83 key++;
84 name++;
85 }
86
87 if (*key != '\0') {
88 return 0;
89 }
90
91 if (*name == SETTINGS_NAME_SEPARATOR) {
92 if (next) {
93 *next = name + 1;
94 }
95 return 1;
96 }
97
98 if ((*name == SETTINGS_NAME_END) || (*name == '\0')) {
99 return 1;
100 }
101
102 return 0;
103 }
104
settings_name_next(const char * name,const char ** next)105 int settings_name_next(const char *name, const char **next)
106 {
107 int rc = 0;
108
109 if (next) {
110 *next = NULL;
111 }
112
113 if (!name) {
114 return 0;
115 }
116
117 /* name might come from flash directly, in flash the name would end
118 * with '=' or '\0' depending how storage is done. Flash reading is
119 * limited to what can be read
120 */
121 while ((*name != '\0') && (*name != SETTINGS_NAME_END) &&
122 (*name != SETTINGS_NAME_SEPARATOR)) {
123 rc++;
124 name++;
125 }
126
127 if (*name == SETTINGS_NAME_SEPARATOR) {
128 if (next) {
129 *next = name + 1;
130 }
131 return rc;
132 }
133
134 return rc;
135 }
136
settings_parse_and_lookup(const char * name,const char ** next)137 struct settings_handler_static *settings_parse_and_lookup(const char *name,
138 const char **next)
139 {
140 struct settings_handler_static *bestmatch;
141 const char *tmpnext;
142
143 bestmatch = NULL;
144 if (next) {
145 *next = NULL;
146 }
147
148 STRUCT_SECTION_FOREACH(settings_handler_static, ch) {
149 if (!settings_name_steq(name, ch->name, &tmpnext)) {
150 continue;
151 }
152 if (!bestmatch) {
153 bestmatch = ch;
154 if (next) {
155 *next = tmpnext;
156 }
157 continue;
158 }
159 if (settings_name_steq(ch->name, bestmatch->name, NULL)) {
160 bestmatch = ch;
161 if (next) {
162 *next = tmpnext;
163 }
164 }
165 }
166
167 #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS)
168 struct settings_handler *ch;
169
170 SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) {
171 if (!settings_name_steq(name, ch->name, &tmpnext)) {
172 continue;
173 }
174 if (!bestmatch) {
175 bestmatch = (struct settings_handler_static *)ch;
176 if (next) {
177 *next = tmpnext;
178 }
179 continue;
180 }
181 if (settings_name_steq(ch->name, bestmatch->name, NULL)) {
182 bestmatch = (struct settings_handler_static *)ch;
183 if (next) {
184 *next = tmpnext;
185 }
186 }
187 }
188 #endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */
189 return bestmatch;
190 }
191
settings_call_set_handler(const char * name,size_t len,settings_read_cb read_cb,void * read_cb_arg,const struct settings_load_arg * load_arg)192 int settings_call_set_handler(const char *name,
193 size_t len,
194 settings_read_cb read_cb,
195 void *read_cb_arg,
196 const struct settings_load_arg *load_arg)
197 {
198 int rc;
199 const char *name_key = name;
200
201 if (load_arg && load_arg->subtree &&
202 !settings_name_steq(name, load_arg->subtree, &name_key)) {
203 return 0;
204 }
205
206 if (load_arg && load_arg->cb) {
207 rc = load_arg->cb(name_key, len, read_cb, read_cb_arg,
208 load_arg->param);
209 } else {
210 struct settings_handler_static *ch;
211
212 ch = settings_parse_and_lookup(name, &name_key);
213 if (!ch) {
214 return 0;
215 }
216
217 rc = ch->h_set(name_key, len, read_cb, read_cb_arg);
218
219 if (rc != 0) {
220 LOG_ERR("set-value failure. key: %s error(%d)",
221 name, rc);
222 /* Ignoring the error */
223 rc = 0;
224 } else {
225 LOG_DBG("set-value OK. key: %s",
226 name);
227 }
228 }
229 return rc;
230 }
231
settings_commit(void)232 int settings_commit(void)
233 {
234 return settings_commit_subtree(NULL);
235 }
236
settings_commit_subtree(const char * subtree)237 int settings_commit_subtree(const char *subtree)
238 {
239 int rc;
240 int rc2;
241
242 rc = 0;
243
244 STRUCT_SECTION_FOREACH(settings_handler_static, ch) {
245 if (subtree && !settings_name_steq(ch->name, subtree, NULL)) {
246 continue;
247 }
248 if (ch->h_commit) {
249 rc2 = ch->h_commit();
250 if (!rc) {
251 rc = rc2;
252 }
253 }
254 }
255
256 #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS)
257 struct settings_handler *ch;
258 SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) {
259 if (subtree && !settings_name_steq(ch->name, subtree, NULL)) {
260 continue;
261 }
262 if (ch->h_commit) {
263 rc2 = ch->h_commit();
264 if (!rc) {
265 rc = rc2;
266 }
267 }
268 }
269 #endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */
270
271 return rc;
272 }
273