EM-ODP  3.7.0
Event Machine on ODP
em_libconfig.c
1 /*
2  * Copyright (c) 2018, Nokia Solutions and Networks
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * * Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * Copyright (c) 2018, Linaro Limited
31  * All rights reserved.
32  *
33  * SPDX-License-Identifier: BSD-3-Clause
34  */
35 
36 #include "em_include.h"
37 #include "include/em_libconfig_config.h"
38 
39 #define SETTING_NAME_LEN 64
40 #define SETTING_PATH_LEN 256
41 
42 int em_libconfig_init_global(libconfig_t *libconfig)
43 {
44  const char *filename;
45  const char *vers;
46  const char *vers_rt;
47  const char *impl;
48  const char *impl_rt;
49  config_t *config = &libconfig->cfg_default;
50  config_t *config_rt = &libconfig->cfg_runtime;
51  const char *impl_field = "em_implementation";
52  const char *vers_field = "config_file_version";
53 
54  config_init(config);
55  config_init(config_rt);
57 
58  if (!config_read_string(config, config_builtin)) {
59  EM_PRINT("Failed to read default config: %s(%d): %s\n",
60  config_error_file(config), config_error_line(config),
61  config_error_text(config));
62  goto fail;
63  }
64 
65  filename = getenv("EM_CONFIG_FILE");
66  if (filename == NULL)
67  return 0;
68 
69  EM_PRINT("EM CONFIG FILE: %s\n", filename);
70 
71  if (!config_read_file(config_rt, filename)) {
72  EM_PRINT(" ERROR: failed to read config file: %s(%d): %s\n\n",
73  config_error_file(config_rt),
74  config_error_line(config_rt),
75  config_error_text(config_rt));
76  goto fail;
77  }
78 
79  /* Check runtime configuration's implementation name and version */
80  if (!config_lookup_string(config, impl_field, &impl) ||
81  !config_lookup_string(config_rt, impl_field, &impl_rt)) {
82  EM_PRINT(" ERROR: missing mandatory field: %s\n\n",
83  impl_field);
84  goto fail;
85  }
86  if (!config_lookup_string(config, vers_field, &vers) ||
87  !config_lookup_string(config_rt, vers_field, &vers_rt)) {
88  EM_PRINT(" ERROR: missing mandatory field: %s\n\n",
89  vers_field);
90  goto fail;
91  }
92  if (strcmp(impl, impl_rt)) {
93  EM_PRINT(" ERROR: EM implementation name mismatch:\n"
94  " Expected: \"%s\"\n"
95  " Found: \"%s\"\n\n", impl, impl_rt);
96  goto fail;
97  }
98  if (strcmp(vers, vers_rt)) {
99  EM_PRINT(" ERROR: config file version number mismatch:\n"
100  " Expected: \"%s\"\n"
101  " Found: \"%s\"\n\n", vers, vers_rt);
102  goto fail;
103  }
104 
106  return 0;
107 fail:
108  EM_PRINT("Config file failure\n");
109  config_destroy(config);
110  config_destroy(config_rt);
111  return -1;
112 }
113 
114 int em_libconfig_term_global(libconfig_t *libconfig)
115 {
116  config_destroy(&libconfig->cfg_default);
117  config_destroy(&libconfig->cfg_runtime);
118 
119  return 0;
120 }
121 
122 int em_libconfig_lookup_int(const libconfig_t *libconfig, const char *path,
123  int *value /*out*/)
124 {
125  int ret_def = CONFIG_FALSE;
126  int ret_rt = CONFIG_FALSE;
127 
128  ret_def = config_lookup_int(&libconfig->cfg_default, path, value);
129 
130  /* Runtime option overrides default value */
131  ret_rt = config_lookup_int(&libconfig->cfg_runtime, path, value);
132 
133  return (ret_def == CONFIG_TRUE || ret_rt == CONFIG_TRUE) ? 1 : 0;
134 }
135 
136 int em_libconfig_lookup_int64(const libconfig_t *libconfig, const char *path,
137  int64_t *value /*out*/)
138 {
139  int ret_def = CONFIG_FALSE;
140  int ret_rt = CONFIG_FALSE;
141  long long value_ll = 0;
142 
143  ret_def = config_lookup_int64(&libconfig->cfg_default, path, &value_ll);
144 
145  /* Runtime option overrides default value */
146  ret_rt = config_lookup_int64(&libconfig->cfg_runtime, path, &value_ll);
147 
148  if (ret_def == CONFIG_TRUE || ret_rt == CONFIG_TRUE) {
149  *value = (int64_t)value_ll;
150  return 1; /* success! */
151  }
152 
153  return 0; /* fail */
154 }
155 
156 int em_libconfig_lookup_bool(const libconfig_t *libconfig, const char *path,
157  bool *value /*out*/)
158 {
159  int ret_def = CONFIG_FALSE;
160  int ret_rt = CONFIG_FALSE;
161  int cfg_value = 0;
162  int ret_val = 0;
163 
164  ret_def = config_lookup_bool(&libconfig->cfg_default, path, &cfg_value);
165 
166  /* Runtime option overrides default value */
167  ret_rt = config_lookup_bool(&libconfig->cfg_runtime, path, &cfg_value);
168 
169  if (ret_def == CONFIG_TRUE || ret_rt == CONFIG_TRUE) {
170  *value = cfg_value ? true : false;
171  ret_val = 1;
172  }
173 
174  return ret_val;
175 }
176 
177 int em_libconfig_lookup_string(const libconfig_t *libconfig, const char *path,
178  const char **value /*out*/)
179 {
180  int ret_def = CONFIG_FALSE;
181  int ret_rt = CONFIG_FALSE;
182 
183  ret_def = config_lookup_string(&libconfig->cfg_default, path, value);
184 
185  /* Runtime option overrides default value */
186  ret_rt = config_lookup_string(&libconfig->cfg_runtime, path, value);
187 
188  return (ret_def == CONFIG_TRUE || ret_rt == CONFIG_TRUE) ? 1 : 0;
189 }
190 
191 int em_libconfig_lookup_array(const libconfig_t *libconfig, const char *path,
192  int value[/*out*/], int max_num)
193 {
194  const config_t *config;
195  const config_setting_t *setting;
196  int num;
197  int num_out = 0;
198 
199  for (int j = 0; j < 2; j++) {
200  if (j == 0)
201  config = &libconfig->cfg_default;
202  else
203  config = &libconfig->cfg_runtime;
204 
205  setting = config_lookup(config, path);
206 
207  /* Runtime config may not define the array, whereas
208  * the default config has it always defined. When the array
209  * is defined, it must be correctly formatted.
210  */
211  if (setting == NULL)
212  continue;
213 
214  if (config_setting_is_array(setting) == CONFIG_FALSE)
215  return 0;
216 
217  num = config_setting_length(setting);
218 
219  if (num <= 0 || num > max_num)
220  return 0;
221 
222  for (int i = 0; i < num; i++)
223  value[i] = config_setting_get_int_elem(setting, i);
224 
225  num_out = num;
226  }
227 
228  /* Number of elements copied */
229  return num_out;
230 }
231 
232 void em_libconfig_lookup(const libconfig_t *libconfig, const char *path,
233  libconfig_setting_t **setting_default/*out*/,
234  libconfig_setting_t **setting_runtime/*out*/)
235 {
236  *setting_default = config_lookup(&libconfig->cfg_default, path);
237  *setting_runtime = config_lookup(&libconfig->cfg_runtime, path);
238 }
239 
240 int em_libconfig_setting_lookup_int(const libconfig_setting_t *setting,
241  const char *name, int *value/*out*/)
242 {
243  return config_setting_lookup_int(setting, name, value);
244 }
245 
246 const libconfig_list_t *
247 em_libconfig_setting_get_list(const libconfig_setting_t *setting, const char *name)
248 {
249  const libconfig_list_t *list_setting;
250 
251  list_setting = config_setting_get_member(setting, name);
252 
253  if (list_setting && config_setting_is_list(list_setting))
254  return list_setting;
255 
256  return NULL;
257 }
258 
259 int em_libconfig_list_length(const libconfig_list_t *list)
260 {
261  return config_setting_length(list);
262 }
263 
264 static uint32_t path_get_depth(const char *path, char delim)
265 {
266  const char *p = path;
267  uint32_t depth = 1; /*Depth is 1 when path contains no delimiter*/
268 
269  while (*p) {
270  if (*p == delim)
271  depth++;
272  p++;
273  }
274 
275  return depth;
276 }
277 
278 /* Get second last setting and the last setting name specified in path from the
279  * list element at index. More specifically, for path 'a.b.c.d', this function
280  * gets second last setting 'c' from list element at index and the last setting
281  * name 'd'.
282  */
283 static int setting_get_child(const config_setting_t *parent, const char *path,
284  const char *delim, const uint32_t depth,
285  char *name/*out*/, config_setting_t **child/*out*/)
286 {
287  char *saveptr; /*Used internally by strtok_r()*/
288  const char *member_name;
289  char path_cp[SETTING_PATH_LEN];
290 
291  /* strtok requires non const char pointer */
292  strncpy(path_cp, path, SETTING_PATH_LEN - 1);
293  path_cp[SETTING_PATH_LEN - 1] = '\0';
294 
295  /* Get second last setting */
296  member_name = strtok_r(path_cp, delim, &saveptr);
297  if (!member_name)
298  return -1;
299 
300  for (uint32_t i = 0; i < depth - 1; i++) {
301  *child = config_setting_get_member(parent, member_name);
302 
303  if (!(*child))
304  return -1;
305 
306  parent = *child;
307  member_name = strtok_r(NULL, delim, &saveptr);
308 
309  if (!member_name)
310  return -1;
311  }
312 
313  /* Get last setting name */
314  strncpy(name, member_name, SETTING_NAME_LEN - 1);
315  name[SETTING_NAME_LEN - 1] = '\0';
316  return 0;
317 }
318 
319 /* Get second last setting and the last setting name specified in path from the
320  * list element at index. More specifically, for path 'a.b.c.d', this function
321  * gets second last setting 'c' from list element at index and the last setting
322  * name 'd'.
323  *
324  * name[out] Pointer where last setting name will be stored
325  * setting[out] Pointer where second last setting will be stored
326  */
327 static int list_get_setting(const libconfig_list_t *list, int index,
328  const char *path, char *name/*out*/,
329  config_setting_t **setting/*out*/)
330 {
331  uint32_t depth;
332  config_setting_t *element;
333  char delim[] = ".";
334 
335  element = config_setting_get_elem(list, index);
336  if (!element) {
337  EM_LOG(EM_LOG_ERR, "List element %d does not exist\n", index);
338  return -1;
339  }
340 
341  depth = path_get_depth(path, delim[0]);
342  if (depth < 2) {/*Only one level of setting in path, e.g., 'a'*/
343  *setting = element;
344  strncpy(name, path, SETTING_NAME_LEN - 1);
345  name[SETTING_NAME_LEN - 1] = '\0';
346  return 0;
347  }
348 
349  /*Get second last setting and the last setting name*/
350  return setting_get_child(element, path, delim, depth, name, setting);
351 }
352 
353 libconfig_group_t *em_libconfig_list_lookup_group(const libconfig_list_t *list,
354  int index, const char *path)
355 {
356  char name[SETTING_NAME_LEN];
357  config_setting_t *setting;
358  libconfig_group_t *group;
359 
360  if (list_get_setting(list, index, path, name, &setting) < 0)
361  return NULL;
362 
363  group = config_setting_get_member(setting, name);
364  if (group && config_setting_is_group(group))
365  return group;
366 
367  return NULL;
368 }
369 
370 int em_libconfig_list_lookup_int(const libconfig_list_t *list, int index,
371  const char *path, int *value/*out*/)
372 {
373  char name[SETTING_NAME_LEN];
374  config_setting_t *setting;
375  const config_setting_t *member;
376 
377  if (list_get_setting(list, index, path, name, &setting) < 0)
378  return -1; /*Parent setting not found*/
379 
380  member = config_setting_get_member(setting, name);
381  if (!member) /*Setting not found*/
382  return -1;
383 
384  return config_setting_lookup_int(setting, name, value);
385 }
386 
387 int em_libconfig_list_lookup_bool(const libconfig_list_t *list, int index,
388  const char *path, bool *value/*out*/)
389 {
390  int cfg_value;
391  char name[SETTING_NAME_LEN];
392  config_setting_t *setting;
393  const config_setting_t *member;
394 
395  if (list_get_setting(list, index, path, name, &setting) < 0)
396  return -1; /*Parent setting not found*/
397 
398  member = config_setting_get_member(setting, name);
399  if (!member) /*Setting not found*/
400  return -1;
401 
402  if (!config_setting_lookup_bool(setting, name, &cfg_value))
403  return 0;
404 
405  *value = cfg_value ? true : false;
406  return 1;
407 }
408 
409 int em_libconfig_list_lookup_string(const libconfig_list_t *list, int index,
410  const char *path, const char **value/*out*/)
411 {
412  char name[SETTING_NAME_LEN];
413  config_setting_t *setting;
414  const config_setting_t *member;
415 
416  if (list_get_setting(list, index, path, name, &setting) < 0)
417  return -1; /*Parent setting not found*/
418 
419  member = config_setting_get_member(setting, name);
420  if (!member) /*Setting not found*/
421  return -1;
422 
423  return config_setting_lookup_string(setting, name, value);
424 }
425 
426 /* Get second last setting and the last setting name specified in path from
427  * the given group. More specifically, for path 'a.b.c.d', this function
428  * gets second last setting 'c' from group and the last setting name 'd'.
429  *
430  * name[out] Pointer where last setting name will be stored
431  * setting[out] Pointer where second last setting will be stored
432  */
433 static int group_get_setting(libconfig_list_t *group, const char *path,
434  char *name/*out*/, config_setting_t **setting/*out*/)
435 {
436  uint32_t depth;
437  char delim[] = ".";
438 
439  depth = path_get_depth(path, delim[0]);
440  if (depth < 2) {/*No child setting*/
441  *setting = group;
442  strncpy(name, path, SETTING_NAME_LEN - 1);
443  name[SETTING_NAME_LEN - 1] = '\0';
444  return 0;
445  }
446 
447  /*Get child setting*/
448  return setting_get_child(group, path, delim, depth, name, setting);
449 }
450 
451 libconfig_group_t
452 *em_libconfig_group_lookup_group(libconfig_group_t *group, const char *path)
453 {
454  char name[SETTING_NAME_LEN];
455  config_setting_t *setting;
456  libconfig_group_t *group_out;
457 
458  if (group_get_setting(group, path, name, &setting) < 0)
459  return NULL;
460 
461  group_out = config_setting_get_member(setting, name);
462  if (group_out && config_setting_is_group(group_out))
463  return group_out;
464 
465  return NULL;
466 }
467 
468 libconfig_list_t
469 *em_libconfig_group_lookup_list(libconfig_group_t *group, const char *path)
470 {
471  libconfig_list_t *list;
472  config_setting_t *setting;
473  char name[SETTING_NAME_LEN];
474 
475  if (group_get_setting(group, path, name, &setting) < 0)
476  return NULL;
477 
478  list = config_setting_get_member(setting, name);
479  if (list && config_setting_is_list(list))
480  return list;
481 
482  return NULL;
483 }
484 
485 int em_libconfig_group_lookup_int(const libconfig_group_t *group,
486  const char *name, int *value/*out*/)
487 {
488  return config_setting_lookup_int(group, name, value);
489 }
490 
491 int em_libconfig_group_lookup_bool(const libconfig_group_t *group,
492  const char *name, bool *value/*out*/)
493 {
494  int cfg_value;
495 
496  if (!config_setting_lookup_bool(group, name, &cfg_value))
497  return 0;
498 
499  *value = cfg_value ? true : false;
500  return 1;
501 }
502 
503 int em_libconfig_group_lookup_string(const libconfig_group_t *group,
504  const char *name, const char **value/*out*/)
505 {
506  return config_setting_lookup_string(group, name, value);
507 }
508 
509 static int lookup_int(const config_t *cfg,
510  const char *base_path,
511  const char *local_path,
512  const char *name,
513  int *value /*out*/)
514 {
515  char path[256];
516 
517  if (local_path) {
518  snprintf(path, sizeof(path), "%s.%s.%s", base_path,
519  local_path, name);
520  if (config_lookup_int(cfg, path, value) == CONFIG_TRUE)
521  return 1;
522  }
523 
524  snprintf(path, sizeof(path), "%s.%s", base_path, name);
525  if (config_lookup_int(cfg, path, value) == CONFIG_TRUE)
526  return 1;
527 
528  return 0;
529 }
530 
531 int em_libconfig_lookup_ext_int(const libconfig_t *libconfig,
532  const char *base_path, const char *local_path,
533  const char *name, int *value /*out*/)
534 {
535  if (lookup_int(&libconfig->cfg_runtime,
536  base_path, local_path, name, value))
537  return 1;
538 
539  if (lookup_int(&libconfig->cfg_default,
540  base_path, local_path, name, value))
541  return 1;
542 
543  return 0;
544 }
545 
546 int em_libconfig_print(const libconfig_t *libconfig)
547 {
548  int c;
549  /* Temp file for config_write() output. Suppress Coverity warning about tmpfile() usage. */
550  /* coverity[secure_temp] */
551  FILE *file = tmpfile();
552 
553  if (file == NULL)
554  return -1;
555 
556  if (fprintf(file,
557  "\nEM_CONFIG_FILE default values:\n"
558  "-------------------------------\n\n") < 0)
559  goto fail;
560 
561  config_write(&libconfig->cfg_default, file);
562 
563  if (libconfig->has_cfg_runtime) {
564  if (fprintf(file,
565  "\nEM_CONFIG_FILE override values:\n"
566  "--------------------------------\n\n") < 0)
567  goto fail;
568 
569  config_write(&libconfig->cfg_runtime, file);
570  }
571 
572  /* Print temp file to the log */
573  rewind(file);
574  while ((c = fgetc(file)) != EOF)
575  EM_PRINT("%c", (char)c);
576 
577  fclose(file);
578  return 0;
579 
580 fail:
581  fclose(file);
582  return -1;
583 }
libconfig::cfg_runtime
config_t cfg_runtime
Definition: em_libconfig_types.h:56
libconfig::cfg_default
config_t cfg_default
Definition: em_libconfig_types.h:54
em_include.h
libconfig
Definition: em_libconfig_types.h:50
libconfig::has_cfg_runtime
bool has_cfg_runtime
Definition: em_libconfig_types.h:52