#include "config.h"
+#include <limits.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
-#include "common.h"
#include "log.h"
#include "toml_handler.h"
-#define OPT_FIELD_ARRAY_LEN(array) ARRAY_LEN(array) - 1
+#define FOREACH_OPTION(groups, grp, opt, type) \
+ for (grp = groups; grp->name != NULL; grp++) \
+ for (opt = grp->options; opt->id != 0; opt++) \
+ if ((opt->availability == 0) || \
+ (opt->availability & type))
struct rpki_config {
/* tal file path*/
- char *tal;
+ char const *tal;
/* Local repository path */
- char *local_repository;
- /* Enable rsync downloads */
- bool enable_rsync;
+ char const *local_repository;
+ /* Disable rsync downloads */
+ bool disable_rsync;
/* Shuffle uris in tal */
bool shuffle_uris;
/*
unsigned int maximum_certificate_depth;
};
-static int parse_bool(struct option_field *, char *, void *);
-static int parse_u_int(struct option_field *, char *, void *);
-static void _free_rpki_config(struct rpki_config *);
+static void print_usage(FILE *stream);
+
+void print_bool(struct group_fields const *, struct option_field const *,
+ void *);
+void print_u_int(struct group_fields const *, struct option_field const *,
+ void *);
+void print_string(struct group_fields const *, struct option_field const *,
+ void *);
+static int parse_bool(struct option_field const *, char const *, void *);
+static int parse_u_int(struct option_field const *, char const *, void *);
+static int parse_string(struct option_field const *, char const *, void *);
+static int handle_help(struct option_field const *, char *);
+static int handle_usage(struct option_field const *, char *);
+static int handle_version(struct option_field const *, char *);
+static int handle_toml(struct option_field const *, char *);
+static void free_string(void *);
+
+static char const *program_name;
static struct rpki_config rpki_config;
-static struct global_type gt_bool = {
- .id = GTI_BOOL,
- .name = "Boolean",
+static const struct global_type gt_bool = {
+ .has_arg = no_argument,
.size = sizeof(bool),
+ .print = print_bool,
.parse = parse_bool,
- .candidates = "true|false",
+ .arg_doc = "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",
+static const struct global_type gt_u_int = {
+ .has_arg = required_argument,
.size = sizeof(unsigned int),
+ .print = print_u_int,
.parse = parse_u_int,
- .candidates = "NUM",
+ .arg_doc = "<unsigned integer>",
};
-static struct option manual_long_opts[] = {
- {
- .name = "configuration-file",
- .has_arg = required_argument,
- .flag = NULL,
- .val = 'f',
- },
+static const struct global_type gt_string = {
+ .has_arg = required_argument,
+ .size = sizeof(char *),
+ .print = print_string,
+ .parse = parse_string,
+ .free = free_string,
+ .arg_doc = "<string>",
};
+/**
+ * An option that takes no arguments, is not correlated to any rpki_config
+ * fields, and is entirely managed by its handler function.
+ */
+static const struct global_type gt_callback = {
+ .has_arg = no_argument,
+};
-static struct option_field global_fields[] = {
+static const struct option_field global_fields[] = {
{
+ .id = 'h',
+ .name = "help",
+ .type = >_callback,
+ .handler = handle_help,
+ .doc = "Give this help list",
+ .availability = AVAILABILITY_GETOPT,
+ }, {
+ .id = 1000,
+ .name = "usage",
+ .type = >_callback,
+ .handler = handle_usage,
+ .doc = "Give a short usage message",
+ .availability = AVAILABILITY_GETOPT,
+ }, {
+ .id = 'V',
+ .name = "version",
+ .type = >_callback,
+ .handler = handle_version,
+ .doc = "Print program version",
+ .availability = AVAILABILITY_GETOPT,
+ }, {
+ .id = 'f',
+ .name = "configuration-file",
+ .type = >_string,
+ .handler = handle_toml,
+ .doc = "TOML file the configuration will be read from.",
+ .arg_doc = "<file>",
+ .availability = AVAILABILITY_GETOPT,
+ }, {
+ .id = 'r',
.name = "local-repository",
.type = >_string,
- .doc = "Local repository path.",
.offset = offsetof(struct rpki_config, local_repository),
- .has_arg = required_argument,
- .short_opt = 0,
- .required = true,
- .candidates = "path",
+ .doc = "Local repository path.",
+ .arg_doc = "<directory>",
}, {
- .name = "enable-rsync",
+ .id = 1001,
+ .name = "disable-rsync",
.type = >_bool,
+ .offset = offsetof(struct rpki_config, disable_rsync),
.doc = "Enable or disable rsync downloads.",
- .offset = offsetof(struct rpki_config, enable_rsync),
- .has_arg = optional_argument,
- .short_opt = 0,
- .required = false,
},
- { NULL },
+ { 0 },
};
-static struct option_field tal_fields[] = {
+static const struct option_field tal_fields[] = {
{
+ .id = 't',
.name = "tal",
.type = >_string,
- .doc = "TAL file path",
.offset = offsetof(struct rpki_config, tal),
- .has_arg = required_argument,
- .short_opt = 0,
- .required = true,
- .candidates = "file",
+ .doc = "TAL file path",
+ .arg_doc = "<file name>",
}, {
+ .id = 2000,
.name = "shuffle-uris",
.type = >_bool,
- .doc = "Shuffle URIs in the TAL.",
.offset = offsetof(struct rpki_config, shuffle_uris),
- .has_arg = optional_argument,
- .short_opt = 0,
- .required = false,
+ .doc = "Shuffle URIs in the TAL.",
}, {
+ .id = 2001,
.name = "maximum-certificate-depth",
.type = >_u_int,
- .doc = "Prevents arbitrarily long paths and loops.",
.offset = offsetof(struct rpki_config,
maximum_certificate_depth),
- .has_arg = required_argument,
- .short_opt = 0,
+ .doc = "Prevents arbitrarily long paths and loops.",
.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,
+ .max = UINT_MAX - 1,
},
- { NULL },
+ { 0 },
};
-
-
-static struct group_fields fields[] = {
+static const struct group_fields groups[] = {
{
- .group_name = "root",
+ .name = "root",
.options = global_fields,
- .options_len = OPT_FIELD_ARRAY_LEN(global_fields),
- },
- {
- .group_name = "tal",
+ }, {
+ .name = "tal",
.options = tal_fields,
- .options_len = OPT_FIELD_ARRAY_LEN(tal_fields),
},
{ NULL },
};
-static int
-str_to_bool(const char *str, bool *bool_out)
+/**
+ * Returns true if @field is the descriptor of one of the members of the
+ * struct rpki_config structure, false otherwise.
+ * (Alternatively: Returns true if @field->offset is valid, false otherwise.)
+ */
+static bool
+is_rpki_config_field(struct option_field const *field)
{
- if (strcasecmp(str, "true") == 0 || strcasecmp(str, "1") == 0 ||
- strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0) {
- *bool_out = true;
- return 0;
- }
+ return field->handler == NULL;
+}
- if (strcasecmp(str, "false") == 0 || strcasecmp(str, "0") == 0 ||
- strcasecmp(str, "no") == 0 || strcasecmp(str, "off") == 0) {
- *bool_out = false;
- return 0;
- }
+static void *
+get_rpki_config_field(struct option_field const *field)
+{
+ return ((unsigned char *) &rpki_config) + field->offset;
+}
+
+void
+print_bool(struct group_fields const *group, struct option_field const *field,
+ void *_value)
+{
+ bool *value = _value;
+ pr_info("%s.%s: %s", group->name, field->name,
+ (*value) ? "true" : "false");
+}
+
+void
+print_u_int(struct group_fields const *group, struct option_field const *field,
+ void *value)
+{
+ pr_info("%s.%s: %u", group->name, field->name,
+ *((unsigned int *) value));
+}
- return pr_err("Cannot parse '%s' as a bool "
- "(true|false|1|0|yes|no|on|off).", str);
+void
+print_string(struct group_fields const *group, struct option_field const *field,
+ void *value)
+{
+ pr_info("%s.%s: %s", group->name, field->name, *((char **) value));
}
static int
-parse_bool(struct option_field *field, char *str, void *result)
+parse_bool(struct option_field const *field, char const *str, void *result)
{
bool *value = result;
- switch (field->has_arg) {
- case no_argument:
+ if (str == NULL) {
*value = true;
return 0;
- break;
- case optional_argument:
- if (str == NULL) {
- *value = true;
- break;
- }
- /* FALLTHROUGH */
- case required_argument:
- return str_to_bool(str, result);
}
- return 0;
+ if (strcmp(str, "true") == 0) {
+ *value = true;
+ return 0;
+ }
+
+ if (strcmp(str, "false") == 0) {
+ *value = false;
+ return 0;
+ }
+
+ return pr_err("Cannot parse '%s' as a bool (true|false).", str);
}
-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)
+static int
+parse_u_int(struct option_field const *field, char const *str, void *_result)
{
- unsigned long long int parsed;
+ unsigned long parsed;
+ int *result;
+
+ if (field->type->has_arg != required_argument || str == NULL) {
+ return pr_err("Integer options ('%s' in this case) require an argument.",
+ field->name);
+ }
errno = 0;
- parsed = strtoull(str, endptr, 10);
+ parsed = strtoul(str, NULL, 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);
+ if (parsed < field->min || field->max < parsed) {
+ return pr_err("'%lu' is out of bounds (%u-%u).", parsed,
+ field->min, field->max);
+ }
+ result = _result;
*result = parsed;
return 0;
}
static int
-str_to_unsigned_int(const char *str, unsigned int *out, unsigned int min,
- unsigned int max)
+parse_string(struct option_field const *field, char const *str, void *_result)
{
- unsigned long long int result = 0;
- int error;
+ char **result = _result;
- error = str_to_ull(str, NULL, min, max, &result);
+ if (field->type->has_arg != required_argument || str == NULL) {
+ return pr_err("String options ('%s' in this case) require an argument.",
+ field->name);
+ }
- *out = result;
- return error;
+ /* tomlc99 frees @str early, so work with a copy. */
+ *result = strdup(str);
+ return ((*result) != NULL) ? 0 : pr_enomem();
}
static int
-parse_u_int(struct option_field *field, char *str, void *result)
+handle_help(struct option_field const *field, char *arg)
{
- 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);
+ print_usage(stdout);
+ exit(0);
}
static int
-construct_options(struct args_flag **flags, struct option **long_options,
- int *flags_len)
+handle_usage(struct option_field const *field, char *arg)
{
- struct option_field *tmp;
- struct group_fields *tmp_all_fields;
- struct args_flag *result_flags;
- struct option *result_options;
- unsigned int total_len, i, result_idx,
- extra_long_options;
-
- tmp_all_fields = fields;
- total_len = 0;
- while (tmp_all_fields->group_name != NULL) {
- total_len += tmp_all_fields->options_len;
- tmp_all_fields += 1;
- }
-
- /* +1 NULL end, means end of array. */
- result_flags = calloc(total_len + 1, sizeof(struct args_flag));
- if (result_flags == NULL)
- return pr_enomem();
-
- extra_long_options = ARRAY_LEN(manual_long_opts);
-
- result_options = calloc(total_len
- + extra_long_options /* extra options handled manually. */
- + 1, /* long options must end with zeros */
- sizeof(struct option));
- if (result_options == NULL) {
- free(result_flags);
- return pr_enomem();
- }
-
- result_idx = 0;
- tmp_all_fields = fields;
- while (tmp_all_fields->group_name != NULL) {
- tmp = tmp_all_fields->options;
- while(tmp->name != NULL) {
- result_flags[result_idx].field = tmp;
-
- result_options[result_idx].name = tmp->name;
- result_options[result_idx].has_arg = tmp->has_arg;
- result_options[result_idx].val = tmp->short_opt;
- result_options[result_idx].flag = NULL;
-
- result_idx++;
- tmp += 1;
- }
- tmp_all_fields += 1;
- }
-
- for (i = 0; i < extra_long_options; i++) {
- result_options[result_idx].name = manual_long_opts[i].name;
- result_options[result_idx].has_arg = manual_long_opts[i].has_arg;
- result_options[result_idx].val = manual_long_opts[i].val;
- result_options[result_idx].flag = manual_long_opts[i].flag;
-
- result_idx++;
- }
-
- *flags = result_flags;
- *flags_len = total_len;
- *long_options = result_options;
-
- return 0;
+ print_usage(stdout);
+ exit(0);
}
static int
-set_string(void **field, char *str)
+handle_version(struct option_field const *field, char *arg)
{
- char *result;
-
- /* malloc the string, because if the string comes from TOML_HANDLER,
- * the string is freed later in that function. */
- result = malloc(strlen(str) + 1);
- if (result == NULL)
- return pr_enomem();
-
- strcpy(result, str);
- *field = result;
+ printf("0.0.1\n");
+ exit(0);
+}
- return 0;
+static int
+handle_toml(struct option_field const *field, char *file_name)
+{
+ return set_config_from_file(file_name);
}
static void
-set_config_param_for_string(void **field, void **config_param)
+free_string(void *_string)
{
- *config_param = *field;
+ char **string = _string;
+ free(*string);
}
-int
-handle_option(struct rpki_config *config, struct option_field *field, char *str)
+static bool
+is_alphanumeric(int chara)
{
- 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;
+ return ('a' <= chara && chara <= 'z')
+ || ('A' <= chara && chara <= 'Z')
+ || ('0' <= chara && chara <= '9');
+}
- if (field->type == >_string) {
- error = set_string(config_param, str);
- if (error)
- return error;
- set_config_param_for_string(config_param, &config_param);
- } else if (field->type->parse != NULL){
- error = field->type->parse(field, str, config_param);
+/**
+ * "struct option" is the array that getopt expects.
+ * "struct args_flag" is our option metadata.
+ */
+static int
+construct_getopt_options(struct option **_long_opts, char **_short_opts)
+{
+ struct group_fields const *group;
+ struct option_field const *opt;
+ struct option *long_opts;
+ char *short_opts;
+ unsigned int total_long_options;
+ unsigned int total_short_options;
+
+ total_long_options = 0;
+ total_short_options = 0;
+ FOREACH_OPTION(groups, group, opt, AVAILABILITY_GETOPT) {
+ total_long_options++;
+ if (is_alphanumeric(opt->id)) {
+ total_short_options++;
+ if (opt->type->has_arg != no_argument)
+ total_short_options++; /* ":" */
+ }
}
- if (error)
- return error;
+ /* +1 NULL end, means end of array. */
+ long_opts = calloc(total_long_options + 1, sizeof(struct option));
+ if (long_opts == NULL)
+ return pr_enomem();
+ short_opts = malloc(total_short_options + 1);
+ if (short_opts == NULL) {
+ free(long_opts);
+ return pr_enomem();
+ }
- if (field->validate != NULL)
- error = field->validate(field, config_param);
- else if (field->type->validate != NULL)
- error = field->type->validate(field, config_param);
+ *_long_opts = long_opts;
+ *_short_opts = short_opts;
+
+ FOREACH_OPTION(groups, group, opt, AVAILABILITY_GETOPT) {
+ long_opts->name = opt->name;
+ long_opts->has_arg = opt->type->has_arg;
+ long_opts->flag = NULL;
+ long_opts->val = opt->id;
+ long_opts++;
+
+ if (is_alphanumeric(opt->id)) {
+ *short_opts = opt->id;
+ short_opts++;
+ if (opt->type->has_arg != no_argument) {
+ *short_opts = ':';
+ short_opts++;
+ }
+ }
+ }
- return error;
+ *short_opts = '\0';
+ return 0;
}
int
-check_missing_flags(struct args_flag *flag)
+parse_option(struct option_field const *field, char const *str)
{
- char *candidate = NULL;
+ return field->type->parse(field, str,
+ get_rpki_config_field(field));
+}
- if (flag->is_set)
- return 0;
- if (!flag->field->required)
- return 0;
+static void
+print_config(void)
+{
+ struct group_fields const *grp;
+ struct option_field const *opt;
- printf("Missing param: %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;
- }
+ pr_info("Configuration {");
+ pr_indent_add();
- printf("\n");
+ FOREACH_OPTION(groups, grp, opt, 0xFFFF)
+ if (is_rpki_config_field(opt) && opt->type->print != NULL)
+ opt->type->print(grp, opt, get_rpki_config_field(opt));
- return -ENOENT;
+ pr_indent_rm();
+ pr_info("}");
}
-static void
-print_config(struct rpki_config *config)
+static int
+set_default_values(void)
{
- 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("}");
+ rpki_config.tal = NULL;
+ rpki_config.local_repository = strdup("repository/");
+ if (rpki_config.local_repository == NULL)
+ return pr_enomem();
+ rpki_config.disable_rsync = false;
+ rpki_config.shuffle_uris = false;
+ rpki_config.maximum_certificate_depth = 32;
+ return 0;
}
-static void
-set_default_values(struct rpki_config *config)
+static int
+validate_config(void)
{
- config->enable_rsync = true;
- config->local_repository = NULL;
- config->maximum_certificate_depth = 32;
- config->shuffle_uris = false;
- config->tal = NULL;
+ return (rpki_config.tal != NULL)
+ ? 0
+ : pr_err("The TAL file (--tal) is mandatory.");
}
-static void _print_usage(bool only_required)
+static void
+print_usage(FILE *stream)
{
- struct option_field *tmp;
- struct group_fields *tmp_all_fields;
- char *candidates;
- bool required;
-
- get_group_fields(&tmp_all_fields);
-
- while (tmp_all_fields->group_name != NULL) {
- tmp = tmp_all_fields->options;
- while(tmp->name != NULL) {
- required = tmp->required;
-
- if (only_required != required) {
- tmp += 1;
- continue;
- }
+ struct group_fields const *group;
+ struct option_field const *option;
+ char const *arg_doc;
- fprintf(stderr, " ");
+ fprintf(stream, "Usage: %s\n", program_name);
- if (!required)
- fprintf(stderr, "[");
- fprintf(stderr, "--%s", tmp->name);
+ FOREACH_OPTION(groups, group, option, AVAILABILITY_GETOPT) {
+ fprintf(stream, "\t[");
+ fprintf(stream, "--%s", option->name);
- if (tmp->candidates != NULL)
- candidates = tmp->candidates;
- else if (tmp->type->candidates != NULL)
- candidates = tmp->type->candidates;
- else
- candidates = NULL;
+ if (option->arg_doc != NULL)
+ arg_doc = option->arg_doc;
+ else if (option->type->arg_doc != NULL)
+ arg_doc = option->type->arg_doc;
+ else
+ arg_doc = NULL;
- switch (tmp->has_arg) {
- case no_argument:
- break;
- case optional_argument:
- if(candidates == NULL)
- break;
- fprintf(stderr, "=<%s>", candidates);
- break;
- case required_argument:
- if(candidates == NULL)
- break;
- fprintf(stderr, " <%s>", candidates);
- break;
- default:
+ switch (option->type->has_arg) {
+ case no_argument:
+ break;
+ case optional_argument:
+ case required_argument:
+ if(arg_doc == NULL)
break;
- }
- if (!required)
- fprintf(stderr, "]");
- tmp += 1;
+ fprintf(stream, "=%s", arg_doc);
+ break;
}
- tmp_all_fields += 1;
- }
+ fprintf(stream, "]\n");
+ }
}
-void
-print_usage(char *progname)
+static int
+handle_opt(int opt)
{
- /*
- * TODO openbsd styleguide said use "getprogname" to set the progam
- * name.
- */
- fprintf(stderr, "usage: %s", progname);
-
- fprintf(stderr, " [-f <config_file>] "
- "[--configuration-file <config_file>]");
-
- _print_usage(true);
- _print_usage(false);
+ struct group_fields const *group;
+ struct option_field const *option;
+
+ FOREACH_OPTION(groups, group, option, AVAILABILITY_GETOPT) {
+ if (option->id == opt) {
+ return is_rpki_config_field(option)
+ ? parse_option(option, optarg)
+ : option->handler(option, optarg);
+ }
+ }
- fprintf(stderr, "\n");
- exit(1);
+ pr_err("Unrecognized option: %d", opt);
+ return -ESRCH;
}
int
handle_flags_config(int argc, char **argv)
{
- struct args_flag *flags;
- struct option *long_options;
- struct rpki_config config;
- int opt, indexptr, flags_len, error;
-
- set_default_values(&config);
+ struct option *long_opts;
+ char *short_opts;
+ int opt;
+ int error;
- long_options = NULL;
- flags = NULL;
- flags_len = 0;
+ program_name = argv[0];
+ error = set_default_values();
+ if (error)
+ return error;
- error = construct_options(&flags, &long_options, &flags_len);
+ long_opts = NULL;
+ short_opts = NULL;
+ error = construct_getopt_options(&long_opts, &short_opts);
if (error)
- return error; /* Error msg already printed. */
-
- while ((opt = getopt_long(argc, argv, "f:", long_options, &indexptr))
- != -1)
- switch (opt) {
- case 0:
- flags[indexptr].is_set = true;
- error = handle_option(&config, flags[indexptr].field,
- optarg);
- if (error) {
- print_usage(argv[0]);
- goto end;
- }
- break;
- case 'f':
- error = set_config_from_file(optarg, &config, flags);
- if (error) {
- print_usage(argv[0]);
- goto end;
- }
- break;
- default:
- print_usage(argv[0]);
- error = -EINVAL;
- goto end;
- }
+ goto end; /* Error msg already printed. */
- for (indexptr = 0; indexptr < flags_len; indexptr++)
- error |= check_missing_flags(&flags[indexptr]);
+ while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL))
+ != -1) {
+ error = handle_opt(opt);
+ if (error)
+ goto end;
+ }
- if (error) {
- print_usage(argv[0]);
+ /*
+ * This triggers when the user runs something like
+ * `rpki-validator disable-rsync` instead of
+ * `rpki-validator --disable-rsync`.
+ * This program does not have unflagged payload.
+ */
+ if (optind < argc) {
+ error = pr_err("I don't know what '%s' is.", argv[optind]);
goto end;
}
- print_config(&config);
- config_set(&config);
+ error = validate_config();
end:
if (error)
- _free_rpki_config(&config);
+ free_rpki_config();
+ else
+ print_config();
- free(flags);
- free(long_options);
+ free(long_opts);
+ free(short_opts);
return error;
}
void
-get_group_fields(struct group_fields **group_fields)
+get_group_fields(struct group_fields const **group_fields)
{
- if (group_fields)
- *group_fields = fields;
-}
-
-void
-config_set(struct rpki_config *new)
-{
- rpki_config = *new;
+ *group_fields = groups;
}
char const *
bool
config_get_enable_rsync(void)
{
- return rpki_config.enable_rsync;
+ return !rpki_config.disable_rsync;
}
bool
return rpki_config.maximum_certificate_depth;
}
-static void
-_free_rpki_config(struct rpki_config *config)
-{
- if (config->local_repository != NULL)
- free(config->local_repository);
-
- if (config->tal != NULL)
- free(config->tal);
-}
-
void
free_rpki_config(void)
{
- _free_rpki_config(&rpki_config);
+ struct group_fields const *group;
+ struct option_field const *option;
+
+ FOREACH_OPTION(groups, group, option, 0xFFFF)
+ if (is_rpki_config_field(option) && option->type->free != NULL)
+ option->type->free(get_rpki_config_field(option));
}