@@ -64,9 +64,6 @@ bool mgos_sys_config_is_initialized(void) {
64
64
static mgos_config_validator_fn * s_validators ;
65
65
static int s_num_validators ;
66
66
67
- static int load_config_file (const char * filename , const char * acl ,
68
- bool check_try , bool delete_try ,
69
- struct mgos_config * cfg );
70
67
static bool mgos_sys_config_load_level_internal (struct mgos_config * cfg ,
71
68
enum mgos_config_level level ,
72
69
bool check_try ,
@@ -94,6 +91,138 @@ void mgos_expand_placeholders(const struct mg_str src, struct mg_str *str) {
94
91
}
95
92
}
96
93
94
+ static bool load_config (const char * name , struct mg_str cfg_data ,
95
+ const char * acl , const struct mgos_conf_entry * schema ,
96
+ void * cfg ) {
97
+ bool result = true;
98
+ /* Make a temporary copy, in case it gets overridden while loading. */
99
+ char * acl_copy = (acl != NULL ? strdup (acl ) : NULL );
100
+ if (!mgos_conf_parse (cfg_data , acl_copy , schema , cfg )) {
101
+ LOG (LL_ERROR , ("Failed to parse %s" , name ));
102
+ result = false;
103
+ }
104
+ free (acl_copy );
105
+ return result ;
106
+ }
107
+
108
+ static bool load_config_file (const char * filename , const char * acl ,
109
+ bool check_try , bool delete_try ,
110
+ const struct mgos_conf_entry * schema , void * cfg ) {
111
+ char * data = NULL ;
112
+ size_t size ;
113
+ bool result = false;
114
+ struct stat st ;
115
+ char tfn_buf [32 ], * try_filename = tfn_buf ;
116
+ // See if we have "${filename}.try" and prefer that.
117
+ // Delete the file immediately after loading.
118
+ if (check_try &&
119
+ mg_asprintf (& try_filename , sizeof (tfn_buf ), "%s%s" , filename ,
120
+ CONF_FILE_TRY_SUFFIX ) > 0 &&
121
+ stat (try_filename , & st ) == 0 ) {
122
+ filename = try_filename ;
123
+ } else {
124
+ if (try_filename != tfn_buf ) free (try_filename );
125
+ try_filename = NULL ;
126
+ }
127
+ if (stat (filename , & st ) != 0 ) {
128
+ goto out ;
129
+ }
130
+ LOG (LL_DEBUG , ("Loading %s" , filename ));
131
+ data = cs_read_file (filename , & size );
132
+ if (data == NULL ) {
133
+ goto out ;
134
+ }
135
+ result = load_config (filename , mg_mk_str_n (data , size ), acl , schema , cfg );
136
+
137
+ out :
138
+ free (data );
139
+ if (try_filename != NULL ) {
140
+ if (delete_try ) remove (try_filename );
141
+ if (try_filename != tfn_buf ) free (try_filename );
142
+ }
143
+ return result ;
144
+ }
145
+
146
+ /*
147
+ * Parse config JSON from a VFS device.
148
+ * `spec` should specify device name and offset (`name,offset`).
149
+ * `offset` is optional and defaults to 0.
150
+ * JSON data must be terminated with NUL or 0xff.
151
+ */
152
+ void mgos_conf_parse_dev (const char * spec , const char * acl ,
153
+ const struct mgos_conf_entry * schema , void * cfg ) {
154
+ char * data = NULL , * data2 = NULL ;
155
+ struct mg_str entry , dev_name = MG_NULL_STR , s ;
156
+ struct mgos_vfs_dev * dev = NULL ;
157
+ size_t i = 0 , offset = 0 , dev_size = 0 , data_size = 0 , data_len = 0 ;
158
+ while (spec != NULL && i < 2 ) {
159
+ spec = mg_next_comma_list_entry (spec , & entry , NULL );
160
+ if (entry .len == 0 ) break ;
161
+ switch (i ) {
162
+ case 0 : {
163
+ dev_name = mg_strdup_nul (entry );
164
+ break ;
165
+ }
166
+ case 1 : {
167
+ struct mg_str tmp = mg_strdup_nul (entry );
168
+ offset = (size_t ) atoi (tmp .p );
169
+ mg_strfree (& tmp );
170
+ break ;
171
+ }
172
+ }
173
+ i ++ ;
174
+ }
175
+ if (dev_name .len == 0 ) goto out ;
176
+ dev = mgos_vfs_dev_open (dev_name .p );
177
+ if (dev == NULL ) goto out ;
178
+ dev_size = mgos_vfs_dev_get_size (dev );
179
+ if (dev_size == 0 ) goto out ;
180
+ while (data_size < dev_size ) {
181
+ const char * end ;
182
+ data_size += 128 ;
183
+ if (data_size > dev_size ) data_size = dev_size ;
184
+ data2 = realloc (data , data_size );
185
+ if (data2 == NULL ) goto out ;
186
+ data = data2 ;
187
+ if (mgos_vfs_dev_read (dev , offset + data_len , data_size - data_len ,
188
+ data + data_len ) != MGOS_VFS_DEV_ERR_NONE ) {
189
+ goto out ;
190
+ }
191
+ // If it doesn't look like JSON, abort early.
192
+ if (data [0 ] != '{' ) {
193
+ LOG (LL_INFO , ("Not a valid config" ));
194
+ goto out ;
195
+ }
196
+ s = mg_mk_str_n (data + data_len , data_size - data_len );
197
+ end = mg_strchr (s , '\0' );
198
+ if (end == NULL ) {
199
+ // We allow 0xff termination to make it even more friendlt to the user.
200
+ // 0xff is the zero value for NOR flash and is not valid JSON, so it's ok.
201
+ end = mg_strchr (s , '\xff' );
202
+ }
203
+ if (end != NULL ) {
204
+ data_len += (end - s .p );
205
+ break ;
206
+ }
207
+ data_len += 128 ;
208
+ }
209
+ if (data_len == dev_size ) goto out ;
210
+ LOG (LL_DEBUG , ("Applying dev %s off %d len %d" , dev_name .p , (int ) offset ,
211
+ (int ) data_len ));
212
+ load_config (spec , mg_mk_str_n (data , data_len ), acl , schema , cfg );
213
+
214
+ out :
215
+ mg_strfree (& dev_name );
216
+ mgos_vfs_dev_close (dev );
217
+ free (data );
218
+ return ;
219
+ }
220
+
221
+ #define PARSE_CONFIG_DEV_LEVEL (l ) \
222
+ if (i == l) { \
223
+ mgos_conf_parse_dev(CS_STRINGIFY_MACRO(MGOS_CONFIG_DEV_##l), acl, sch, \
224
+ cfg); \
225
+ }
97
226
static bool mgos_sys_config_load_level_internal (struct mgos_config * cfg ,
98
227
enum mgos_config_level level ,
99
228
bool check_try ,
@@ -106,14 +235,39 @@ static bool mgos_sys_config_load_level_internal(struct mgos_config *cfg,
106
235
// Start with compiled-in defaults.
107
236
mgos_config_set_defaults (cfg );
108
237
const char * acl = "*" ;
238
+ const struct mgos_conf_entry * sch = mgos_config_schema ();
109
239
for (i = 1 ; i <= (int ) level ; i ++ ) {
240
+ #ifdef MGOS_CONFIG_DEV_1
241
+ PARSE_CONFIG_DEV_LEVEL (1 );
242
+ #endif
243
+ #ifdef MGOS_CONFIG_DEV_2
244
+ PARSE_CONFIG_DEV_LEVEL (2 );
245
+ #endif
246
+ #ifdef MGOS_CONFIG_DEV_3
247
+ PARSE_CONFIG_DEV_LEVEL (3 );
248
+ #endif
249
+ #ifdef MGOS_CONFIG_DEV_4
250
+ PARSE_CONFIG_DEV_LEVEL (4 );
251
+ #endif
252
+ #ifdef MGOS_CONFIG_DEV_5
253
+ PARSE_CONFIG_DEV_LEVEL (5 );
254
+ #endif
255
+ #ifdef MGOS_CONFIG_DEV_6
256
+ PARSE_CONFIG_DEV_LEVEL (6 );
257
+ #endif
258
+ #ifdef MGOS_CONFIG_DEV_7
259
+ PARSE_CONFIG_DEV_LEVEL (7 );
260
+ #endif
261
+ #ifdef MGOS_CONFIG_DEV_8
262
+ PARSE_CONFIG_DEV_LEVEL (8 );
263
+ #endif
110
264
fname [CONF_USER_FILE_NUM_IDX ] = '0' + i ;
111
265
/* Backward compat: load conf_vendor.json at level 5.5 */
112
266
if (i == 6 ) {
113
- load_config_file (CONF_VENDOR_FILE , cfg -> conf_acl , false, false, cfg );
267
+ load_config_file (CONF_VENDOR_FILE , cfg -> conf_acl , false, false, sch , cfg );
114
268
acl = cfg -> conf_acl ;
115
269
}
116
- if (!load_config_file (fname , acl , check_try , delete_try , cfg )) {
270
+ if (!load_config_file (fname , acl , check_try , delete_try , sch , cfg )) {
117
271
// Nothing to do, all the overlays are optional.
118
272
}
119
273
acl = cfg -> conf_acl ;
@@ -206,53 +360,6 @@ void mgos_config_reset(int level) {
206
360
}
207
361
}
208
362
209
- static int load_config_file (const char * filename , const char * acl ,
210
- bool check_try , bool delete_try ,
211
- struct mgos_config * cfg ) {
212
- char * data = NULL , * acl_copy = NULL ;
213
- size_t size ;
214
- int result = 1 ;
215
- struct stat st ;
216
- char tfn_buf [32 ], * try_filename = tfn_buf ;
217
- // See if we have "${filename}.try" and prefer that.
218
- // Delete the file immediately after loading.
219
- if (check_try &&
220
- mg_asprintf (& try_filename , sizeof (tfn_buf ), "%s%s" , filename ,
221
- CONF_FILE_TRY_SUFFIX ) > 0 &&
222
- stat (try_filename , & st ) == 0 ) {
223
- filename = try_filename ;
224
- } else {
225
- if (try_filename != tfn_buf ) free (try_filename );
226
- try_filename = NULL ;
227
- }
228
- if (stat (filename , & st ) != 0 ) {
229
- result = 0 ;
230
- goto clean ;
231
- }
232
- LOG (LL_INFO , ("Loading %s" , filename ));
233
- data = cs_read_file (filename , & size );
234
- if (data == NULL ) {
235
- result = 0 ;
236
- goto clean ;
237
- }
238
- /* Make a temporary copy, in case it gets overridden while loading. */
239
- acl_copy = (acl != NULL ? strdup (acl ) : NULL );
240
- if (!mgos_conf_parse (mg_mk_str_n (data , size ), acl_copy , mgos_config_schema (),
241
- cfg )) {
242
- LOG (LL_ERROR , ("Failed to parse %s" , filename ));
243
- result = 0 ;
244
- goto clean ;
245
- }
246
- clean :
247
- free (data );
248
- free (acl_copy );
249
- if (try_filename != NULL ) {
250
- if (delete_try ) remove (try_filename );
251
- if (try_filename != tfn_buf ) free (try_filename );
252
- }
253
- return result ;
254
- }
255
-
256
363
void mbedtls_debug_set_threshold (int threshold );
257
364
258
365
enum mgos_init_result mgos_sys_config_init (void ) {
@@ -289,7 +396,7 @@ enum mgos_init_result mgos_sys_config_init(void) {
289
396
/* Successfully loaded system config. Try overrides - they are optional. */
290
397
load_config_file (CONF_USER_FILE , mgos_sys_config_get_conf_acl (),
291
398
true /* check_try */ , true /* delete_try */ ,
292
- & mgos_sys_config );
399
+ mgos_config_schema (), & mgos_sys_config );
293
400
294
401
s_initialized = true;
295
402
0 commit comments