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