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 <limits.h>
13 #include <zephyr/kernel.h>
14
15 #include <zephyr/settings/settings.h>
16 #include "settings_priv.h"
17 #include <zephyr/types.h>
18 #include <zephyr/sys/iterable_sections.h>
19 #include <zephyr/logging/log.h>
20 LOG_MODULE_REGISTER(settings, CONFIG_SETTINGS_LOG_LEVEL);
21
22 #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS)
23 sys_slist_t settings_handlers;
24 #endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */
25
26 K_MUTEX_DEFINE(settings_lock);
27
28
29 void settings_store_init(void);
30
settings_init(void)31 void settings_init(void)
32 {
33 #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS)
34 sys_slist_init(&settings_handlers);
35 #endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */
36 settings_store_init();
37 }
38
39 #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS)
settings_register_with_cprio(struct settings_handler * handler,int cprio)40 int settings_register_with_cprio(struct settings_handler *handler, int cprio)
41 {
42 int rc = 0;
43
44 STRUCT_SECTION_FOREACH(settings_handler_static, ch) {
45 if (strcmp(handler->name, ch->name) == 0) {
46 return -EEXIST;
47 }
48 }
49
50 k_mutex_lock(&settings_lock, K_FOREVER);
51
52 struct settings_handler *ch;
53 SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) {
54 if (strcmp(handler->name, ch->name) == 0) {
55 rc = -EEXIST;
56 goto end;
57 }
58 }
59
60 handler->cprio = cprio;
61 sys_slist_append(&settings_handlers, &handler->node);
62
63 end:
64 k_mutex_unlock(&settings_lock);
65 return rc;
66 }
67
settings_register(struct settings_handler * handler)68 int settings_register(struct settings_handler *handler)
69 {
70 return settings_register_with_cprio(handler, 0);
71 }
72 #endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */
73
settings_name_steq(const char * name,const char * key,const char ** next)74 int settings_name_steq(const char *name, const char *key, const char **next)
75 {
76 if (next) {
77 *next = NULL;
78 }
79
80 if ((!name) || (!key)) {
81 return 0;
82 }
83
84 /* name might come from flash directly, in flash the name would end
85 * with '=' or '\0' depending how storage is done. Flash reading is
86 * limited to what can be read
87 */
88
89 while ((*key != '\0') && (*key == *name) &&
90 (*name != '\0') && (*name != SETTINGS_NAME_END)) {
91 key++;
92 name++;
93 }
94
95 if (*key != '\0') {
96 return 0;
97 }
98
99 if (*name == SETTINGS_NAME_SEPARATOR) {
100 if (next) {
101 *next = name + 1;
102 }
103 return 1;
104 }
105
106 if ((*name == SETTINGS_NAME_END) || (*name == '\0')) {
107 return 1;
108 }
109
110 return 0;
111 }
112
settings_name_next(const char * name,const char ** next)113 int settings_name_next(const char *name, const char **next)
114 {
115 int rc = 0;
116
117 if (next) {
118 *next = NULL;
119 }
120
121 if (!name) {
122 return 0;
123 }
124
125 /* name might come from flash directly, in flash the name would end
126 * with '=' or '\0' depending how storage is done. Flash reading is
127 * limited to what can be read
128 */
129 while ((*name != '\0') && (*name != SETTINGS_NAME_END) &&
130 (*name != SETTINGS_NAME_SEPARATOR)) {
131 rc++;
132 name++;
133 }
134
135 if (*name == SETTINGS_NAME_SEPARATOR) {
136 if (next) {
137 *next = name + 1;
138 }
139 return rc;
140 }
141
142 return rc;
143 }
144
settings_parse_and_lookup(const char * name,const char ** next)145 struct settings_handler_static *settings_parse_and_lookup(const char *name,
146 const char **next)
147 {
148 struct settings_handler_static *bestmatch;
149 const char *tmpnext;
150
151 bestmatch = NULL;
152 if (next) {
153 *next = NULL;
154 }
155
156 STRUCT_SECTION_FOREACH(settings_handler_static, ch) {
157 if (!settings_name_steq(name, ch->name, &tmpnext)) {
158 continue;
159 }
160 if (!bestmatch) {
161 bestmatch = ch;
162 if (next) {
163 *next = tmpnext;
164 }
165 continue;
166 }
167 if (settings_name_steq(ch->name, bestmatch->name, NULL)) {
168 bestmatch = ch;
169 if (next) {
170 *next = tmpnext;
171 }
172 }
173 }
174
175 #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS)
176 struct settings_handler *ch;
177
178 SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) {
179 if (!settings_name_steq(name, ch->name, &tmpnext)) {
180 continue;
181 }
182 if (!bestmatch) {
183 bestmatch = (struct settings_handler_static *)ch;
184 if (next) {
185 *next = tmpnext;
186 }
187 continue;
188 }
189 if (settings_name_steq(ch->name, bestmatch->name, NULL)) {
190 bestmatch = (struct settings_handler_static *)ch;
191 if (next) {
192 *next = tmpnext;
193 }
194 }
195 }
196 #endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */
197 return bestmatch;
198 }
199
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)200 int settings_call_set_handler(const char *name,
201 size_t len,
202 settings_read_cb read_cb,
203 void *read_cb_arg,
204 const struct settings_load_arg *load_arg)
205 {
206 int rc;
207 const char *name_key = name;
208
209 if (load_arg && load_arg->subtree &&
210 !settings_name_steq(name, load_arg->subtree, &name_key)) {
211 return 0;
212 }
213
214 if (load_arg && load_arg->cb) {
215 rc = load_arg->cb(name_key, len, read_cb, read_cb_arg,
216 load_arg->param);
217 } else {
218 struct settings_handler_static *ch;
219
220 ch = settings_parse_and_lookup(name, &name_key);
221 if (!ch) {
222 return 0;
223 }
224
225 rc = ch->h_set(name_key, len, read_cb, read_cb_arg);
226
227 if (rc != 0) {
228 LOG_ERR("set-value failure. key: %s error(%d)",
229 name, rc);
230 /* Ignoring the error */
231 rc = 0;
232 } else {
233 LOG_DBG("set-value OK. key: %s",
234 name);
235 }
236 }
237 return rc;
238 }
239
settings_commit(void)240 int settings_commit(void)
241 {
242 return settings_commit_subtree(NULL);
243 }
244
set_next_cprio(int handler_cprio,int cprio,int next_cprio)245 static int set_next_cprio(int handler_cprio, int cprio, int next_cprio)
246 {
247 if (handler_cprio <= cprio) {
248 return next_cprio;
249 }
250
251 /* If cprio and next_cprio are identical then next_cprio has not
252 * yet been set to any value and its initialized to the first
253 * handler_cprio above cprio.
254 */
255 if (cprio == next_cprio) {
256 return handler_cprio;
257 }
258
259 return MIN(handler_cprio, next_cprio);
260 }
261
settings_commit_subtree(const char * subtree)262 int settings_commit_subtree(const char *subtree)
263 {
264 int rc;
265 int rc2;
266 int cprio = INT_MIN;
267
268 rc = 0;
269
270 while (true) {
271 int next_cprio = cprio;
272
273 STRUCT_SECTION_FOREACH(settings_handler_static, ch) {
274 if (subtree && !settings_name_steq(ch->name, subtree, NULL)) {
275 continue;
276 }
277
278 if (ch->h_commit) {
279 next_cprio = set_next_cprio(ch->cprio, cprio, next_cprio);
280 if (ch->cprio != cprio) {
281 continue;
282 }
283
284 rc2 = ch->h_commit();
285 if (!rc) {
286 rc = rc2;
287 }
288 }
289 }
290
291 if (IS_ENABLED(CONFIG_SETTINGS_DYNAMIC_HANDLERS)) {
292 struct settings_handler *ch;
293
294 SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) {
295 if (subtree && !settings_name_steq(ch->name, subtree, NULL)) {
296 continue;
297 }
298
299 if (ch->h_commit) {
300 next_cprio = set_next_cprio(ch->cprio, cprio, next_cprio);
301 if (ch->cprio != cprio) {
302 continue;
303 }
304
305 rc2 = ch->h_commit();
306 if (!rc) {
307 rc = rc2;
308 }
309 }
310 }
311 }
312
313 if (cprio == next_cprio) {
314 break;
315 }
316
317 cprio = next_cprio;
318 }
319
320 return rc;
321 }
322