1 /*
2 * Copyright (c) 2018 Nordic Semiconductor ASA
3 * Copyright (c) 2015 Runtime Inc
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <string.h>
9 #include <stdio.h>
10
11 #include <zephyr/types.h>
12 #include <stddef.h>
13 #include <sys/types.h>
14 #include <errno.h>
15 #include <zephyr/kernel.h>
16 #include <zephyr/sys/iterable_sections.h>
17 #include <zephyr/settings/settings.h>
18 #include "settings_priv.h"
19
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_DECLARE(settings, CONFIG_SETTINGS_LOG_LEVEL);
22
23 sys_slist_t settings_load_srcs;
24 struct settings_store *settings_save_dst;
25
settings_src_register(struct settings_store * cs)26 void settings_src_register(struct settings_store *cs)
27 {
28 sys_slist_append(&settings_load_srcs, &cs->cs_next);
29 }
30
settings_dst_register(struct settings_store * cs)31 void settings_dst_register(struct settings_store *cs)
32 {
33 settings_save_dst = cs;
34 }
35
settings_load(void)36 int settings_load(void)
37 {
38 return settings_load_subtree(NULL);
39 }
40
settings_load_subtree(const char * subtree)41 int settings_load_subtree(const char *subtree)
42 {
43 struct settings_store *cs;
44 int rc;
45 const struct settings_load_arg arg = {
46 .subtree = subtree
47 };
48
49 /*
50 * for every config store
51 * load config
52 * apply config
53 * commit all
54 */
55 settings_lock_take();
56 SYS_SLIST_FOR_EACH_CONTAINER(&settings_load_srcs, cs, cs_next) {
57 cs->cs_itf->csi_load(cs, &arg);
58 }
59 rc = settings_commit_subtree(subtree);
60 settings_lock_release();
61 return rc;
62 }
63
settings_load_subtree_direct(const char * subtree,settings_load_direct_cb cb,void * param)64 int settings_load_subtree_direct(
65 const char *subtree,
66 settings_load_direct_cb cb,
67 void *param)
68 {
69 struct settings_store *cs;
70
71 const struct settings_load_arg arg = {
72 .subtree = subtree,
73 .cb = cb,
74 .param = param
75 };
76 /*
77 * for every config store
78 * load config
79 * apply config
80 * commit all
81 */
82 settings_lock_take();
83 SYS_SLIST_FOR_EACH_CONTAINER(&settings_load_srcs, cs, cs_next) {
84 cs->cs_itf->csi_load(cs, &arg);
85 }
86 settings_lock_release();
87 return 0;
88 }
89
90 struct default_param {
91 void *buf;
92 size_t buf_len;
93 size_t *val_len;
94 };
95
96 /* Default callback to set a Key/Value pair */
settings_set_default_cb(const char * name,size_t len,settings_read_cb read_cb,void * cb_arg,void * param)97 static int settings_set_default_cb(const char *name, size_t len, settings_read_cb read_cb,
98 void *cb_arg, void *param)
99 {
100 int rc = 0;
101 const char *next;
102 size_t name_len;
103 struct default_param *dest = (struct default_param *)param;
104
105 name_len = settings_name_next(name, &next);
106 if (name_len == 0) {
107 rc = read_cb(cb_arg, dest->buf, MIN(dest->buf_len, len));
108 *dest->val_len = len;
109 }
110
111 return rc;
112 }
113
114 /* Default callback to get the value's length of the Key defined by name.
115 * Returns the value's length in the provided `param` pointer
116 */
settings_get_val_len_default_cb(const char * name,size_t len,settings_read_cb read_cb __maybe_unused,void * cb_arg __maybe_unused,void * param)117 static int settings_get_val_len_default_cb(const char *name, size_t len,
118 settings_read_cb read_cb __maybe_unused,
119 void *cb_arg __maybe_unused, void *param)
120 {
121 const char *next;
122 size_t name_len;
123 size_t *val_len = (size_t *)param;
124
125 name_len = settings_name_next(name, &next);
126 if (name_len == 0) {
127 *val_len = len;
128 }
129
130 return 0;
131 }
132
133 /* Gets the value's size if the Key defined by name is in the persistent storage,
134 * Returns 0 if the Key doesn't exist.
135 */
settings_get_val_len(const char * name)136 ssize_t settings_get_val_len(const char *name)
137 {
138 struct settings_store *cs;
139 int rc = 0;
140 size_t val_len = 0;
141
142 /*
143 * for every config store that supports this function
144 * get the value's length.
145 */
146 settings_lock_take();
147 SYS_SLIST_FOR_EACH_CONTAINER(&settings_load_srcs, cs, cs_next) {
148 if (cs->cs_itf->csi_get_val_len) {
149 val_len = cs->cs_itf->csi_get_val_len(cs, name);
150 } else {
151 const struct settings_load_arg arg = {
152 .subtree = name,
153 .cb = &settings_get_val_len_default_cb,
154 .param = &val_len
155 };
156 rc = cs->cs_itf->csi_load(cs, &arg);
157 }
158 }
159 settings_lock_release();
160
161 if (rc >= 0) {
162 return val_len;
163 }
164
165 return rc;
166 }
167
168 /* Load a single key/value from persistent storage */
settings_load_one(const char * name,void * buf,size_t buf_len)169 ssize_t settings_load_one(const char *name, void *buf, size_t buf_len)
170 {
171 struct settings_store *cs;
172 size_t val_len = 0;
173 int rc = 0;
174
175 /*
176 * For every config store that defines csi_load_one() function use it.
177 * Otherwise, use the csi_load() function to load the key/value pair
178 */
179 settings_lock_take();
180 SYS_SLIST_FOR_EACH_CONTAINER(&settings_load_srcs, cs, cs_next) {
181 if (cs->cs_itf->csi_load_one) {
182 rc = cs->cs_itf->csi_load_one(cs, name, (char *)buf, buf_len);
183 val_len = (rc >= 0) ? rc : 0;
184 } else {
185 struct default_param param = {
186 .buf = buf,
187 .buf_len = buf_len,
188 .val_len = &val_len
189 };
190 const struct settings_load_arg arg = {
191 .subtree = name,
192 .cb = &settings_set_default_cb,
193 .param = ¶m
194 };
195 rc = cs->cs_itf->csi_load(cs, &arg);
196 }
197 }
198 settings_lock_release();
199
200 if (rc >= 0) {
201 return val_len;
202 }
203 return rc;
204 }
205
206 /*
207 * Append a single value to persisted config. Don't store duplicate value.
208 */
settings_save_one(const char * name,const void * value,size_t val_len)209 int settings_save_one(const char *name, const void *value, size_t val_len)
210 {
211 int rc;
212 struct settings_store *cs;
213
214 cs = settings_save_dst;
215 if (!cs) {
216 return -ENOENT;
217 }
218
219 settings_lock_take();
220
221 rc = cs->cs_itf->csi_save(cs, name, (char *)value, val_len);
222
223 settings_lock_release();
224
225 return rc;
226 }
227
settings_delete(const char * name)228 int settings_delete(const char *name)
229 {
230 return settings_save_one(name, NULL, 0);
231 }
232
settings_save(void)233 int settings_save(void)
234 {
235 return settings_save_subtree(NULL);
236 }
237
settings_save_subtree(const char * subtree)238 int settings_save_subtree(const char *subtree)
239 {
240 struct settings_store *cs;
241 int rc;
242 int rc2;
243
244 cs = settings_save_dst;
245 if (!cs) {
246 return -ENOENT;
247 }
248
249 if (cs->cs_itf->csi_save_start) {
250 cs->cs_itf->csi_save_start(cs);
251 }
252 rc = 0;
253
254 STRUCT_SECTION_FOREACH(settings_handler_static, ch) {
255 if (subtree && !settings_name_steq(ch->name, subtree, NULL)) {
256 continue;
257 }
258 if (ch->h_export) {
259 rc2 = ch->h_export(settings_save_one);
260 if (!rc) {
261 rc = rc2;
262 }
263 }
264 }
265
266 #if defined(CONFIG_SETTINGS_DYNAMIC_HANDLERS)
267 struct settings_handler *ch;
268 SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) {
269 if (subtree && !settings_name_steq(ch->name, subtree, NULL)) {
270 continue;
271 }
272 if (ch->h_export) {
273 rc2 = ch->h_export(settings_save_one);
274 if (!rc) {
275 rc = rc2;
276 }
277 }
278 }
279 #endif /* CONFIG_SETTINGS_DYNAMIC_HANDLERS */
280
281 if (cs->cs_itf->csi_save_end) {
282 cs->cs_itf->csi_save_end(cs);
283 }
284 return rc;
285 }
286
settings_storage_get(void ** storage)287 int settings_storage_get(void **storage)
288 {
289 struct settings_store *cs = settings_save_dst;
290
291 if (!cs) {
292 return -ENOENT;
293 }
294
295 if (cs->cs_itf->csi_storage_get) {
296 *storage = cs->cs_itf->csi_storage_get(cs);
297 }
298
299 return 0;
300 }
301
settings_store_init(void)302 void settings_store_init(void)
303 {
304 sys_slist_init(&settings_load_srcs);
305 }
306