#include "config.h"
#include <stdio.h>
-#include <strings.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
-struct args_flag {
- struct option_field *field;
- bool is_set;
+struct rpki_config {
+ /* tal file path*/
+ char *tal;
+ /* Local repository path */
+ char *local_repository;
+ /* Enable rsync downloads */
+ bool enable_rsync;
+ /* Shuffle uris in tal */
+ bool shuffle_uris;
+ /*
+ * rfc6487#section-7.2, last paragraph.
+ * Prevents arbitrarily long paths and loops.
+ */
+ 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 struct rpki_config config;
+static struct rpki_config rpki_config;
static struct global_type gt_bool = {
.id = GTI_BOOL,
.name = "Boolean",
.size = sizeof(bool),
.parse = parse_bool,
- .candidates = "true false",
+ .candidates = "true|false",
};
static struct global_type gt_string = {
.name = "Unsigned Int",
.size = sizeof(unsigned int),
.parse = parse_u_int,
- .candidates = "Unsigned Int",
+ .candidates = "NUM",
+};
+
+static struct option manual_long_opts[] = {
+ {
+ .name = "configuration-file",
+ .has_arg = required_argument,
+ .flag = NULL,
+ .val = 'f',
+ },
};
+
static struct option_field global_fields[] = {
{
.name = "local-repository",
.short_opt = 0,
.min = 1,
/**
- * It cannot be UINT_MAX, because then the actual number will overflow
- * and will never be bigger than this.
+ * 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 struct group_fields fields[] = {
+ {
+ .group_name = "root",
+ .options = global_fields,
+ .options_len = OPT_FIELD_ARRAY_LEN(global_fields),
+ },
+ {
+ .group_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)
{
*value = true;
return 0;
break;
- case required_argument:
case optional_argument:
- if (field->has_arg == optional_argument && str == NULL) {
+ if (str == NULL) {
*value = true;
- return 0;
+ break;
}
- /**
- * XXX: (fine) GETOPT should had ensure that the code did
- * not reach here for this particular case.
- * */
+ /* FALLTHROUGH */
+ case required_argument:
return str_to_bool(str, result);
- break;
- }
-
- if (str == NULL) {
- *value = true;
- return 0;
}
- return str_to_bool(str, result);
+ return 0;
}
static int str_to_ull(const char *str, char **endptr,
construct_options(struct args_flag **flags, struct option **long_options,
int *flags_len)
{
+ struct option_field *tmp;
+ struct group_fields *tmp_all_fields;
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;
+ 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;
+ }
- result_flags = calloc(total_len, sizeof(struct args_flag));
+ /* +1 NULL end, means end of array. */
+ result_flags = calloc(total_len + 1, 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));
+ 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;
- 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++;
+ 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 < 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;
+ 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++;
}
return 0;
}
-static void
+static int
set_string(void **field, char *str)
{
- *field = str;
+ 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;
+
+ return 0;
}
static void
config_param += field->offset;
if (field->type == >_string) {
- set_string(config_param, str);
+ 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);
if (!flag->field->required)
return 0;
- printf("Missing flag --%s", flag->field->name);
+ printf("Missing param: %s", flag->field->name);
switch (flag->field->has_arg) {
case no_argument:
break;
pr_debug_rm("}");
}
+static void
+set_default_values(struct rpki_config *config)
+{
+ config->enable_rsync = true;
+ config->local_repository = NULL;
+ config->maximum_certificate_depth = 32;
+ config->shuffle_uris = false;
+ config->tal = NULL;
+}
+
+static void _print_usage(bool only_required)
+{
+ 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;
+ }
+
+ fprintf(stderr, " ");
+
+ if (!required)
+ fprintf(stderr, "[");
+ fprintf(stderr, "--%s", tmp->name);
+
+ if (tmp->candidates != NULL)
+ candidates = tmp->candidates;
+ else if (tmp->type->candidates != NULL)
+ candidates = tmp->type->candidates;
+ else
+ candidates = 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:
+ break;
+ }
+ if (!required)
+ fprintf(stderr, "]");
+ tmp += 1;
+ }
+ tmp_all_fields += 1;
+ }
+
+}
+
+
+void
+print_usage(char *progname)
+{
+ /*
+ * 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);
+
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
int
-handle_flags_config(int argc, char **argv, struct rpki_config *config)
+handle_flags_config(int argc, char **argv)
{
struct args_flag *flags;
struct option *long_options;
- int opt, indexptr, flags_len, error = 0;
+ struct rpki_config config;
+ int opt, indexptr, flags_len, error;
+
+ set_default_values(&config);
- flags = NULL;
long_options = NULL;
+ flags = NULL;
+ flags_len = 0;
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) {
+ 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,
+ error = handle_option(&config, flags[indexptr].field,
optarg);
+ if (error) {
+ print_usage(argv[0]);
+ goto end;
+ }
break;
- default:
- error = pr_err("some usage hints.");/* TODO */
+ case 'f':
+ error = set_config_from_file(optarg, &config, flags);
+ if (error) {
+ print_usage(argv[0]);
+ goto end;
+ }
break;
- }
-
- if (error)
+ default:
+ print_usage(argv[0]);
+ error = -EINVAL;
goto end;
- }
+ }
- for (indexptr = 0; indexptr < flags_len; indexptr++) {
+ for (indexptr = 0; indexptr < flags_len; indexptr++)
error |= check_missing_flags(&flags[indexptr]);
+
+ if (error) {
+ print_usage(argv[0]);
+ goto end;
}
- print_config(config);
+ print_config(&config);
+ config_set(&config);
end:
+ if (error)
+ _free_rpki_config(&config);
+
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)
+get_group_fields(struct group_fields **group_fields)
{
- if (fields)
- *fields = tal_fields;
- if (len)
- *len = OPT_FIELD_ARRAY_LEN(tal_fields);
+ if (group_fields)
+ *group_fields = fields;
}
void
config_set(struct rpki_config *new)
{
- config = *new;
+ rpki_config = *new;
}
char const *
config_get_tal(void)
{
- return config.tal;
+ return rpki_config.tal;
}
char const *
config_get_local_repository(void)
{
- return config.local_repository;
+ return rpki_config.local_repository;
}
bool
config_get_enable_rsync(void)
{
- return config.enable_rsync;
+ return rpki_config.enable_rsync;
}
bool
config_get_shuffle_uris(void)
{
- return config.shuffle_uris;
+ return rpki_config.shuffle_uris;
}
unsigned int
config_get_max_cert_depth(void)
{
- return config.maximum_certificate_depth;
+ 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);
}
#include "thread_var.h"
#include "uri.h"
-
-static void
-print_config(struct rpki_config *config)
+static int
+find_flag(struct args_flag *flags_handled, char *flag_to_find,
+ struct args_flag **result)
{
- 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("}");
+ int cmp;
+ *result = NULL;
+
+ while(flags_handled->field != NULL) {
+ cmp = strcmp(flags_handled->field->name, flag_to_find);
+ if (cmp == 0) {
+ *result = flags_handled;
+ break;
+ }
+ flags_handled = flags_handled + 1;
+ }
+
+ if (*result == NULL)
+ return pr_crit("Missing parameter %s.", flag_to_find);
+
+ return 0;
}
static int
iterate_fields(struct toml_table_t *table, struct rpki_config *config,
- struct option_field *fields, unsigned int field_len)
+ struct option_field *fields, struct args_flag *flags_handled)
{
- struct option_field *field;
+ struct option_field *tmp_field;
+ struct args_flag *tmp_arg;
const char *result;
char *str;
- int i, error, missing_param;
+ int error;
- missing_param = 0;
+ tmp_field = fields;
+ while (tmp_field->name != NULL) {
+ error = find_flag(flags_handled, tmp_field->name, &tmp_arg);
+ if (error)
+ return error; /* Error msg already printed. */
+ if (tmp_arg->is_set) {
+ tmp_field += 1;
+ continue;
+ }
- for (i = 0; i < field_len; i++) {
- field = &(fields[i]);
- result = toml_raw_in(table, field->name);
+ result = toml_raw_in(table, tmp_field->name);
if (result == 0) {
- if (field->required) {
- printf("Required parameter is missing '%s'\n",
- field->name);
- missing_param |= -ENOENT;
- }
+ tmp_field += 1;
continue;
}
str = (char *) result;
- if (field->type->id == GTI_STRING) {
+ if (tmp_field->type->id == GTI_STRING) {
error = toml_rtos(result, &str);
if (error)
return pr_err("Bad value in '%s'",
- field->name);
+ tmp_field->name);
}
- error = handle_option(config, field, str);
+ error = handle_option(config, tmp_field, str);
if (error)
return error;
+ /* Free returned string from toml */
+ if (tmp_field->type->id == GTI_STRING)
+ free(str);
+
+ tmp_arg->is_set = true;
+ tmp_field += 1;
}
- if (missing_param)
- return missing_param;
return error;
}
static int
-handle_tal_table(struct toml_table_t *tal, struct rpki_config *config)
+toml_to_config(struct toml_table_t *root, struct rpki_config *config,
+ struct args_flag *flags_handled)
{
- 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;
+ struct toml_table_t *toml_table;
+ struct group_fields *group_fields;
int error;
- unsigned int global_len;
+ get_group_fields(&group_fields);
+ if (group_fields == NULL)
+ return 0;
- get_global_fields(&globals, &global_len);
- error = iterate_fields(root, config, globals, global_len);
+ error = iterate_fields(root, config, group_fields->options,
+ flags_handled);
if (error)
return error;
+ group_fields += 1;
- 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");
+ while (group_fields->group_name != NULL) {
+ toml_table = toml_table_in(root, group_fields->group_name);
+ if (toml_table == 0) {
+ group_fields += 1;
+ continue;
+ }
+ error = iterate_fields(toml_table, config,
+ group_fields->options, flags_handled);
+ if (error)
+ return error;
+ group_fields += 1;
+ }
return error;
}
int
-set_config_from_file(char *config_file, struct rpki_config *config)
+set_config_from_file(char *config_file, struct rpki_config *config,
+ struct args_flag *flags_handled)
{
- struct file_contents fc;
+ FILE *file;
+ struct stat stat;
struct toml_table_t *root;
struct rpki_uri uri;
char errbuf[200];
goto end;
}
- error = file_load(&uri, &fc);
+ error = file_open(&uri, &file, &stat);
if (error)
goto end; /* Error msg already printed. */
- root = toml_parse((char *) fc.buffer, errbuf, sizeof(errbuf));
- file_free(&fc);
+ root = toml_parse_file(file, errbuf, sizeof(errbuf));
+ file_close(file);
if (root == NULL) {
error = pr_err("Error while parsing configuration file: %s",
goto end;
}
- error = toml_to_config(root, config);
+ error = toml_to_config(root, config, flags_handled);
toml_free(root);
- print_config(config);
-
end:
return error;
}