]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Merge branch 'master' into args-parser
authordhfelix <daniel.hdz.felix@hotmail.com>
Mon, 11 Feb 2019 22:56:20 +0000 (16:56 -0600)
committerdhfelix <daniel.hdz.felix@hotmail.com>
Mon, 11 Feb 2019 22:56:20 +0000 (16:56 -0600)
Conflicts:
src/config.c
src/config.h
src/main.c

1  2 
src/Makefile.am
src/config.c
src/config.h
src/main.c
src/rsync/rsync.c
src/toml_handler.c

diff --cc src/Makefile.am
index fe0cf7feaa4ae5479025bcf281a8a220a14e38b8,afaebd34df452d210bcca1bce42d60677d976824..2c581e7828a8753fe4620aaf6d68f45065c50771
@@@ -21,8 -22,6 +22,7 @@@ rpki_validator_SOURCES += sorted_array.
  rpki_validator_SOURCES += state.h state.c
  rpki_validator_SOURCES += thread_var.h thread_var.c
  rpki_validator_SOURCES += uri.h uri.c
- rpki_validator_SOURCES += config.h config.c
 +rpki_validator_SOURCES += toml_handler.h toml_handler.c
  
  rpki_validator_SOURCES += rsync/rsync.h rsync/rsync.c
  
diff --cc src/config.c
index df9d526da30c05e28a7a0e4589afba0c915a47b3,f60731ac4eda1821a07495b41030f2af2499c432..6b25b719a00106f38142a5840bc8f18530a24cc1
  #include "config.h"
  
- #include <asm-generic/errno-base.h>
 +#include <stdio.h>
- #include <getopt.h>
 +#include <strings.h>
++#include <errno.h>
++#include <getopt.h>
 +
 +#include "common.h"
 +#include "log.h"
 +
 +#define OPT_FIELD_ARRAY_LEN(array) ARRAY_LEN(array) - 1
 +
- static int parse_bool(struct option_field *, char *, void *);
 +struct args_flag {
 +      struct option_field *field;
 +      bool is_set;
 +};
 +
++static int parse_bool(struct option_field *, char *, void *);
++static int parse_u_int(struct option_field *, char *, void *);
++
+ static struct rpki_config config;
 +static struct global_type gt_bool = {
 +      .id = GTI_BOOL,
 +      .name = "Boolean",
 +      .size = sizeof(bool),
 +      .parse = parse_bool,
 +      .candidates = "true false",
 +};
 +
 +static struct global_type gt_string = {
 +      .id = GTI_STRING,
 +      .name = "String",
 +};
 +
++static struct global_type gt_u_int = {
++      .id = GTI_U_INT,
++      .name = "Unsigned Int",
++      .size = sizeof(unsigned int),
++      .parse = parse_u_int,
++      .candidates = "Unsigned Int",
++};
++
 +static struct option_field global_fields[] = {
 +      {
 +              .name = "local-repository",
 +              .type = &gt_string,
 +              .doc = "Local repository path.",
 +              .offset = offsetof(struct rpki_config, local_repository),
 +              .has_arg = required_argument,
 +              .short_opt = 0,
 +              .required = true,
 +              .candidates = "path",
 +      }, {
 +              .name = "enable-rsync",
 +              .type = &gt_bool,
 +              .doc = "Enable or disable rsync downloads.",
 +              .offset = offsetof(struct rpki_config, enable_rsync),
 +              .has_arg = optional_argument,
 +              .short_opt = 0,
 +              .required = false,
 +      },
 +      { NULL },
 +};
 +
 +static struct option_field tal_fields[] = {
 +      {
 +              .name = "tal",
 +              .type = &gt_string,
 +              .doc = "TAL file path",
 +              .offset = offsetof(struct rpki_config, tal),
 +              .has_arg = required_argument,
 +              .short_opt = 0,
 +              .required = true,
 +              .candidates = "file",
 +      }, {
 +              .name = "shuffle-uris",
 +              .type = &gt_bool,
 +              .doc = "Shuffle URIs in the TAL.",
 +              .offset = offsetof(struct rpki_config, shuffle_uris),
 +              .has_arg = optional_argument,
 +              .short_opt = 0,
 +              .required = false,
++      }, {
++              .name = "maximum-certificate-depth",
++              .type = &gt_u_int,
++              .doc = "Prevents arbitrarily long paths and loops.",
++              .offset = offsetof(struct rpki_config,
++                  maximum_certificate_depth),
++              .has_arg = required_argument,
++              .short_opt = 0,
++              .min = 1,
++              /**
++               * It cannot be UINT_MAX, because then the actual number will overflow
++               * and will never be bigger than this.
++               */
++              .max =  UINT_MAX - 1,
++              .required = false,
 +      },
 +      { NULL },
 +};
 +
- static int str_to_bool(const char *str, bool *bool_out)
++static int
++str_to_bool(const char *str, bool *bool_out)
 +{
 +      if (strcasecmp(str, "true") == 0 || strcasecmp(str, "1") == 0 ||
 +          strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0) {
 +              *bool_out = true;
 +              return 0;
 +      }
 +
 +      if (strcasecmp(str, "false") == 0 || strcasecmp(str, "0") == 0 ||
 +          strcasecmp(str, "no") == 0 || strcasecmp(str, "off") == 0) {
 +              *bool_out = false;
 +              return 0;
 +      }
 +
 +      return pr_err("Cannot parse '%s' as a bool "
 +                      "(true|false|1|0|yes|no|on|off).", str);
 +}
 +
- static int parse_bool(struct option_field *field, char *str, void *result)
++static int
++parse_bool(struct option_field *field, char *str, void *result)
 +{
 +      bool *value = result;
 +
 +      switch (field->has_arg) {
 +      case no_argument:
 +              *value = true;
 +              return 0;
 +              break;
 +      case required_argument:
 +      case optional_argument:
 +              if (field->has_arg == optional_argument && str == NULL) {
 +                      *value = true;
 +                      return 0;
 +              }
 +              /**
 +               * XXX: (fine) GETOPT should had ensure that the code did
 +               * not reach here for this particular case.
 +               * */
 +              return str_to_bool(str, result);
 +              break;
 +      }
 +
 +      if (str == NULL) {
 +              *value = true;
 +              return 0;
 +      }
 +
 +      return str_to_bool(str, result);
 +}
 +
++static int str_to_ull(const char *str, char **endptr,
++    const unsigned long long int min,
++    const unsigned long long int max,
++    unsigned long long int *result)
++{
++      unsigned long long int parsed;
++
++      errno = 0;
++      parsed = strtoull(str, endptr, 10);
++      if (errno)
++              return pr_errno(errno, "'%s' is not an unsigned integer", str);
++
++      if (parsed < min || max < parsed)
++              return pr_err("'%s' is out of bounds (%llu-%llu).", str, min,
++                  max);
++
++      *result = parsed;
++      return 0;
++}
++
++static int
++str_to_unsigned_int(const char *str, unsigned int *out, unsigned int min,
++    unsigned int max)
++{
++      unsigned long long int result = 0;
++      int error;
++
++      error = str_to_ull(str, NULL, min, max, &result);
++
++      *out = result;
++      return error;
++}
++
++static int
++parse_u_int(struct option_field *field, char *str, void *result)
++{
++      unsigned int *value = result;
++
++      if (str == NULL)
++              return pr_err("String cannot be NULL");
++
++      return str_to_unsigned_int(str, value, field->min, field->max);
++}
++
 +static int
 +construct_options(struct args_flag **flags, struct option **long_options,
 +    int *flags_len)
 +{
 +      struct args_flag *result_flags;
 +      struct option_field *global, *tal;
 +      struct option *result_options;
 +      unsigned int global_len, tal_len, total_len, i, result_idx;
 +
 +      get_global_fields(&global, &global_len);
 +      get_tal_fields(&tal, &tal_len);
 +
 +      total_len = global_len + tal_len;
 +
 +      result_flags = calloc(total_len, sizeof(struct args_flag));
 +      if (result_flags == NULL)
 +              return pr_enomem();
 +
 +      /* Long options must end with zeros (+1) */
 +      result_options = calloc(total_len + 1, sizeof(struct option));
 +      if (result_options == NULL) {
 +              free(result_flags);
 +              return pr_enomem();
 +      }
 +
 +      result_idx = 0;
 +      for(i = 0; i < global_len; i++) {
 +              result_flags[result_idx].field = &(global[i]);
 +
 +              result_options[result_idx].name = global[i].name;
 +              result_options[result_idx].has_arg = global[i].has_arg;
 +              result_options[result_idx].val = global[i].short_opt;
 +              result_options[result_idx].flag = NULL;
 +
 +              result_idx++;
 +      }
 +
 +      for(i = 0; i < tal_len; i++) {
 +              result_flags[result_idx].field = &(tal[i]);
 +
 +              result_options[result_idx].name = tal[i].name;
 +              result_options[result_idx].has_arg = tal[i].has_arg;
 +              result_options[result_idx].val = tal[i].short_opt;
 +              result_options[result_idx].flag = NULL;
 +
 +              result_idx++;
 +      }
 +
 +      *flags = result_flags;
 +      *flags_len = total_len;
 +      *long_options = result_options;
 +
 +      return 0;
 +}
 +
 +static void
 +set_string(void **field, char *str)
 +{
 +      *field = str;
 +}
 +
 +static void
 +set_config_param_for_string(void **field, void **config_param)
 +{
 +      *config_param = *field;
 +}
 +
 +int
 +handle_option(struct rpki_config *config, struct option_field *field, char *str)
 +{
 +      void *config_param;
 +      int error = 0;
 +
 +      /**
 +       * TODO Should we use a switch case?
 +       * In order to avoid:
 +       * warning: pointer of type ‘void *’ used in arithmetic
 +       * [-Wpointer-arith]
 +       * https://stackoverflow.com/questions/23357442/
 +       * dynamically-access-member-variable-of-a-structure
 +       */
 +      config_param = config;
 +      config_param += field->offset;
 +
 +      if (field->type == &gt_string) {
 +              set_string(config_param, str);
 +              set_config_param_for_string(config_param, &config_param);
 +      } else if (field->type->parse != NULL){
 +              error = field->type->parse(field, str, config_param);
 +      }
++
 +      if (error)
 +              return error;
 +
 +      if (field->validate != NULL)
 +              error = field->validate(field, config_param);
 +      else if (field->type->validate != NULL)
 +              error = field->type->validate(field, config_param);
 +
 +      return error;
 +}
 +
 +int
 +check_missing_flags(struct args_flag *flag)
 +{
 +      char *candidate = NULL;
 +
 +      if (flag->is_set)
 +              return 0;
 +      if (!flag->field->required)
 +              return 0;
 +
 +      printf("Missing flag --%s", flag->field->name);
 +      switch (flag->field->has_arg) {
 +      case no_argument:
 +              break;
 +      case optional_argument:
 +              if (flag->field->candidates != NULL)
 +                      candidate = flag->field->candidates;
 +              else if (flag->field->type->candidates != NULL)
 +                      candidate = flag->field->type->candidates;
 +              if (candidate != NULL)
 +                      printf("[=%s]", candidate);
 +              break;
 +      case required_argument:
 +              if (flag->field->candidates != NULL)
 +                      candidate = flag->field->candidates;
 +              else if (flag->field->type->candidates != NULL)
 +                      candidate = flag->field->type->candidates;
 +              if (candidate != NULL)
 +                      printf(" <%s>", candidate);
 +              break;
 +      default:
 +              break;
 +      }
 +
 +      printf("\n");
 +
 +      return -ENOENT;
 +}
 +
 +static void
 +print_config(struct rpki_config *config)
 +{
 +      pr_debug("Program configuration");
 +      pr_debug_add("{");
 +      pr_debug("%s: %s", "local-repository", config->local_repository);
 +      pr_debug("%s: %s", "tal", config->tal);
 +      pr_debug("%s: %s", "enable-rsync",
 +          config->enable_rsync ? "true" : "false");
 +      pr_debug("%s: %s", "tal.shuffle-uris",
 +          config->shuffle_uris ? "true" : "false");
++      pr_debug("%s: %u", "tal.maximum-certificate-depth",
++                  config->maximum_certificate_depth);
 +      pr_debug_rm("}");
 +}
 +
 +int
 +handle_flags_config(int argc, char **argv, struct rpki_config *config)
 +{
 +      struct args_flag *flags;
 +      struct option *long_options;
 +      int opt, indexptr, flags_len, error = 0;
 +
 +      flags = NULL;
 +      long_options = NULL;
-       config->flag_config = true;
 +
 +      error = construct_options(&flags, &long_options, &flags_len);
 +      if (error)
 +              return error; /* Error msg already printed. */
 +
 +      while ((opt = getopt_long(argc, argv, "", long_options, &indexptr))
 +          != -1) {
 +              switch (opt) {
 +              case 0:
 +                      flags[indexptr].is_set = true;
 +                      error = handle_option(config, flags[indexptr].field,
 +                          optarg);
 +                      break;
 +              default:
 +                      error = pr_err("some usage hints.");/* TODO */
 +                      break;
 +              }
 +
 +              if (error)
 +                      goto end;
 +      }
 +
 +      for (indexptr = 0; indexptr < flags_len; indexptr++) {
 +              error |= check_missing_flags(&flags[indexptr]);
 +      }
 +
 +      print_config(config);
 +
 +end:
 +      free(flags);
 +      free(long_options);
 +      return error;
 +
 +}
 +
 +void
 +get_global_fields(struct option_field **fields, unsigned int *len)
 +{
 +      if (fields)
 +              *fields = global_fields;
 +      if (len)
 +              *len = OPT_FIELD_ARRAY_LEN(global_fields);
 +}
 +
 +void
 +get_tal_fields(struct option_field **fields, unsigned int *len)
 +{
 +      if (fields)
 +              *fields = tal_fields;
 +      if (len)
 +              *len = OPT_FIELD_ARRAY_LEN(tal_fields);
 +}
++
+ void
+ config_set(struct rpki_config *new)
+ {
+       config = *new;
+ }
+ char const *
+ config_get_tal(void)
+ {
+       return config.tal;
+ }
+ char const *
+ config_get_local_repository(void)
+ {
+       return config.local_repository;
+ }
+ bool
 -config_get_disable_rsync(void)
++config_get_enable_rsync(void)
+ {
 -      return config.disable_rsync;
++      return config.enable_rsync;
+ }
+ bool
+ config_get_shuffle_uris(void)
+ {
+       return config.shuffle_uris;
+ }
+ unsigned int
+ config_get_max_cert_depth(void)
+ {
+       return config.maximum_certificate_depth;
+ }
diff --cc src/config.h
index eb4c01db570008dc7885a9b85c6c35e2c612b522,b49348d0228774c61e2c60a90719924e9a323c3c..54a64e5a1b7f6eab09e5219f028aa84508dcb320
@@@ -9,56 -8,23 +9,68 @@@ struct rpki_config 
        char *tal;
        /* Local repository path */
        char *local_repository;
--      /* Disable rsync downloads */
 -      bool disable_rsync;
++      /* Enable rsync downloads */
 +      bool enable_rsync;
        /* Shuffle uris in tal */
        bool shuffle_uris;
-       /* Configuration file path */
-       bool flag_config;
+       /*
+        * rfc6487#section-7.2, last paragraph.
+        * Prevents arbitrarily long paths and loops.
+        */
+       unsigned int maximum_certificate_depth;
  };
  
 -bool config_get_disable_rsync(void);
 +typedef enum global_type_id {
 +      GTI_BOOL,
 +      GTI_STRING,
++      GTI_U_INT,
 +} global_type_id;
 +
 +struct option_field;
 +
 +typedef void (*print_function)(void *, bool);
 +typedef int (*parse_function)(struct option_field *, char *, void *);
 +/* This function does not need to validate type->size. */
 +typedef int (*validate_function)(struct option_field *, void *);
 +
 +struct global_type {
 +      global_type_id id;
 +      const char *name;
 +      size_t size;
 +      print_function print;
 +      parse_function parse;
 +      validate_function validate;
 +      char *candidates;
 +};
 +
 +struct option_field {
 +      char *name; /* This being NULL means the end of the array. */
 +      struct global_type *type;
 +      const char *doc;
 +      size_t offset;
 +      int has_arg;
 +      char short_opt;
 +      unsigned long min;
 +      unsigned long max;
 +      print_function print; /* Overrides type->print. */
 +      validate_function validate; /* Overrides type->validate. */
 +      char *candidates; /* Overrides type->candidates. */
 +      bool required;
 +};
 +
 +int handle_option(struct rpki_config *, struct option_field *, char *);
 +int handle_flags_config(int , char **, struct rpki_config *);
 +
 +void get_global_fields(struct option_field **, unsigned int *);
 +
 +void get_tal_fields(struct option_field **, unsigned int *);
 +
+ void config_set(struct rpki_config *);
+ char const *config_get_tal(void);
+ char const *config_get_local_repository(void);
++bool config_get_enable_rsync(void);
+ bool config_get_shuffle_uris(void);
+ unsigned int config_get_max_cert_depth(void);
  #endif /* SRC_CONFIG_H_ */
diff --cc src/main.c
index 7f0965b6c2c7ff27edfb182a6a0021f65534acf6,dc44fd62200de8f54b1855313d71193ebec21864..ae826fbd87a7174da65d50fabc2783ea758ea772
@@@ -100,46 -111,97 +112,48 @@@ end
        return error;
  }
  
- static void
- set_default_configuration(struct rpki_config *config)
- {
-       config->enable_rsync = true;
-       config->shuffle_uris = false;
-       config->local_repository = NULL;
-       config->tal = NULL;
- }
  static int
 -parse_max_depth(struct rpki_config *config, char *str)
 +handle_file_config(char *config_file, struct rpki_config *config)
  {
-       config->flag_config = false;
 -      /*
 -       * It cannot be UINT_MAX, because then the actual number will overflow
 -       * and will never be bigger than this.
 -       */
 -      const unsigned int MAX = UINT_MAX - 1;
 -      unsigned long max_depth;
 -
 -      errno = 0;
 -      max_depth = strtoul(str, NULL, 10);
 -      if (errno) {
 -              return pr_errno(errno,
 -                  "'%s' is not an unsigned integer, or is too big (max: %u)",
 -                  str, MAX);
 -      }
 -
 -      if (max_depth > MAX)
 -              return pr_err("The number '%s' is too big (max: %u)", str, MAX);
--
 -      config->maximum_certificate_depth = max_depth;
 -      return 0;
 +      return set_config_from_file(config_file, config);
  }
  
  static int
- handle_args(int argc, char **argv, struct rpki_config *config)
+ handle_args(int argc, char **argv)
  {
 -      int opt, error = 0;
 -
 -      static struct option long_options[] = {
 -              {"tal", no_argument, NULL, 't'},
 -              {"local_repository", required_argument, NULL, 'l'},
 -              {"disable_rsync", no_argument, 0, 'r'},
 -              {"shuffle_uris", no_argument, 0, 's'},
 -              {0,0,0,}
 -      };
+       struct rpki_config config;
 -      config.disable_rsync = false;
 -      config.shuffle_uris = false;
 +      char *config_file;
++      int error;
 -      config.tal = NULL;
++      config.enable_rsync = true;
+       config.local_repository = NULL;
+       config.maximum_certificate_depth = 32;
++      config.shuffle_uris = false;
++      config.tal = NULL;
  
 -      while ((opt = getopt_long(argc, argv, "t:l:rsm:", long_options, NULL))
 -          != -1) {
 -              switch (opt) {
 -              case 't' :
 -                      config.tal = optarg;
 -                      break;
 -              case 'l' :
 -                      config.local_repository = optarg;
 -                      break;
 -              case 'r':
 -                      config.disable_rsync = true;
 -                      break;
 -              case 's':
 -                      config.shuffle_uris = true;
 -                      break;
 -              case 'm':
 -                      error = parse_max_depth(&config, optarg);
 -                      break;
 -              default:
 -                      return pr_err("some usage hints.");/* TODO */
 -              }
 -      }
 -
 -      if (config.tal == NULL) {
 -              fprintf(stderr, "Missing flag --tal <file>\n");
 -              error = -EINVAL;
 +      if (argc == 1) {
 +              return pr_err("Show usage"); /*TODO*/
        }
 -      if (config.local_repository == NULL) {
 -              fprintf(stderr, "Missing flag --local_repository <dir>\n");
 -              error = -EINVAL;
 +      if (strcasecmp(argv[1], "--configuration_file") == 0) {
 +              if (argc == 2) {
 +                      return pr_err("--configuration_file requires a string "
 +                          "as argument.");
 +              }
 +              config_file = argv[2];
 +              argc -= 2;
 +              argv += 2;
-               return handle_file_config(config_file, config);
++              error = handle_file_config(config_file, &config);
++      } else {
++              error = handle_flags_config(argc, argv, &config);
        }
  
-       return handle_flags_config(argc, argv, config);
 -      pr_debug("TAL file : %s", config.tal);
 -      pr_debug("Local repository : %s", config.local_repository);
 -      pr_debug("Disable rsync : %s", config.disable_rsync
 -          ? "true" : "false");
 -      pr_debug("shuffle uris : %s", config.shuffle_uris
 -          ? "true" : "false");
 -      pr_debug("Maximum certificate depth : %u",
 -          config.maximum_certificate_depth);
 -
+       if (!error)
+               config_set(&config);
++
+       return error;
  }
  
 +
  int
  main(int argc, char **argv)
  {
index 61361a61f3a9f52f9efc443f7eabab5cf2e0290f,a0770ba15d90ac573ca4a4246e0d699fabce9900..2072d4e97af93c2cff8f70ca97d31d85574893bf
@@@ -27,13 -27,11 +27,11 @@@ static char const *const RSYNC_PREFIX 
  //static const char *rsync_command[] = {"rsync", "--recursive", "--delete", "--times", NULL};
  
  int
- rsync_init(bool is_rsync_active)
+ rsync_init(void)
  {
        /* Disabling rsync will forever be a useful debugging feature. */
-       if (!is_rsync_active) {
-               execute_rsync = is_rsync_active;
 -      if (config_get_disable_rsync())
++      if (!config_get_enable_rsync())
                return 0;
-       }
  
        rsync_uris = malloc(sizeof(struct uri_list));
        if (rsync_uris == NULL)
@@@ -48,7 -46,7 +46,7 @@@ rsync_destroy(void
  {
        struct uri *uri;
  
-       if (!execute_rsync)
 -      if (config_get_disable_rsync())
++      if (!config_get_enable_rsync())
                return;
  
        while (!SLIST_EMPTY(rsync_uris)) {
@@@ -378,7 -378,7 +378,7 @@@ download_files(struct rpki_uri const *u
  
        prefix_len = strlen(RSYNC_PREFIX);
  
-       if (!execute_rsync)
 -      if (config_get_disable_rsync())
++      if (!config_get_enable_rsync())
                return 0;
  
        if (uri->global_len < prefix_len ||
index 9526d36b9aaeb3c38818b738d4519d3e659a67f1,0000000000000000000000000000000000000000..58bd754ea645bd3047a20410e00cb3490a6d96fd
mode 100644,000000..100644
--- /dev/null
@@@ -1,152 -1,0 +1,154 @@@
 +#include "toml_handler.h"
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include <errno.h>
 +
 +#include <toml.h>
 +
 +#include "file.h"
 +#include "log.h"
 +#include "thread_var.h"
 +#include "uri.h"
 +
 +
 +static void
 +print_config(struct rpki_config *config)
 +{
 +      pr_debug("Program configuration");
 +      pr_debug_add("{");
 +      pr_debug("%s: %s", "local_repository", config->local_repository);
 +      pr_debug("%s: %s", "tal.file", config->tal);
 +      pr_debug("%s: %s", "enable_rsync",
 +          config->enable_rsync ? "true" : "false");
 +      pr_debug("%s: %s", "tal.shuffle_uris",
 +          config->shuffle_uris ? "true" : "false");
++      pr_debug("%s: %u", "tal.maximum-certificate-depth",
++                  config->maximum_certificate_depth);
 +      pr_debug_rm("}");
 +}
 +
 +static int
 +iterate_fields(struct toml_table_t *table, struct rpki_config *config,
 +    struct option_field *fields, unsigned int field_len)
 +{
 +      struct option_field *field;
 +      const char *result;
 +      char *str;
 +      int i, error, missing_param;
 +
 +      missing_param = 0;
 +
 +      for (i = 0; i < field_len; i++) {
 +              field = &(fields[i]);
 +              result = toml_raw_in(table, field->name);
 +              if (result == 0) {
 +                      if (field->required) {
 +                              printf("Required parameter is missing '%s'\n",
 +                                  field->name);
 +                              missing_param |= -ENOENT;
 +                      }
 +                      continue;
 +              }
 +
 +              str = (char *) result;
 +              if (field->type->id == GTI_STRING) {
 +                      error = toml_rtos(result, &str);
 +                      if (error)
 +                              return pr_err("Bad value in '%s'",
 +                                  field->name);
 +              }
 +
 +              error = handle_option(config, field, str);
 +              if (error)
 +                      return error;
 +
 +      }
 +
 +      if (missing_param)
 +              return missing_param;
 +      return error;
 +}
 +
 +static int
 +handle_tal_table(struct toml_table_t *tal, struct rpki_config *config)
 +{
 +      struct option_field *tal_fields;
 +      unsigned int tal_len;
 +
 +      get_tal_fields(&tal_fields, &tal_len);
 +
 +      return iterate_fields(tal, config, tal_fields, tal_len);
 +}
 +
 +static int
 +toml_to_config(struct toml_table_t *root, struct rpki_config *config)
 +{
 +      struct option_field *globals;
 +      struct toml_table_t *tal;
 +      int error;
 +      unsigned int global_len;
 +
 +
 +      get_global_fields(&globals, &global_len);
 +      error = iterate_fields(root, config, globals, global_len);
 +      if (error)
 +              return error;
 +
 +      tal = toml_table_in(root, "tal");
 +      if (tal != 0)
 +              error = handle_tal_table(tal, config);
 +      else
 +              return pr_err("Required table '%s' is missing.", "tal");
 +
 +      return error;
 +}
 +
 +int
 +set_config_from_file(char *config_file, struct rpki_config *config)
 +{
 +      struct file_contents fc;
 +      struct toml_table_t *root;
 +      struct rpki_uri uri;
 +      char errbuf[200];
 +      int error;
 +      bool is_config_file;
 +
 +      /* I think I'm not using this struct correctly but I need it to call
 +       * some functions, so be careful using the struct rpki_uri here.
 +       * Also no needs to be freed. */
 +      uri.global = config_file;
 +      uri.global_len = strlen(config_file);
 +      uri.local = config_file;
 +
 +      is_config_file = uri_has_extension(&uri, ".ini");
 +      is_config_file |= uri_has_extension(&uri, ".toml");
 +      if (!is_config_file) {
 +              error = pr_err("Invalid Config file extension for file '%s'",
 +                  uri.local);
 +              goto end;
 +      }
 +
 +      error = file_load(&uri, &fc);
 +      if (error)
 +              goto end; /* Error msg already printed. */
 +
 +      root = toml_parse((char *) fc.buffer, errbuf, sizeof(errbuf));
 +      file_free(&fc);
 +
 +      if (root == NULL) {
 +              error = pr_err("Error while parsing configuration file: %s",
 +                  errbuf);
 +              goto end;
 +      }
 +
 +      error = toml_to_config(root, config);
 +
 +      toml_free(root);
 +
 +      print_config(config);
 +
 +end:
 +      return error;
 +}