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