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 = &param
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