From ebec053d2c792a896bca58a5ebe5ada40ae1bcc2 Mon Sep 17 00:00:00 2001 From: FoxyHunter Date: Sun, 31 May 2026 09:36:41 +0200 Subject: [PATCH] Feat: load env vars --- src/config.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/config.h | 28 ++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 src/config.c create mode 100644 src/config.h diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..75a3eb9 --- /dev/null +++ b/src/config.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "log.h" + +static int load_env_str(const char *env_name, char **out, int unset) { + const char *env_var = getenv(env_name); + if (!env_var || env_var[0] == '\0') { + log_error("Missing required env var %s", env_name); + return -1; + } + *out = strdup(env_var); + if (!*out) { log_error("Memory allocation failed"); return -1; } + if (unset) unsetenv(env_name); + return 0; +} + +static int load_env_int( + const char *env_name, + int *out, + int min, + int max, + int fallback +) { + const char *env_var = getenv(env_name); + if (!env_var || env_var[0] == '\0') { *out = fallback; return 0; } + + char *end; + errno = 0; + long parsed = strtol(env_var, &end, 10); + + if (errno != 0 || *end != '\0') { + log_error("%s needs to be an integer", env_name); + return -1; + } + if (parsed < min || parsed > max) { + log_error("%s needs to be within range (%d-%d)", env_name, min, max); + return -1; + } + *out = (int)parsed; + return 0; +} + +static int load_env_strs( + const char *env_name, + char ***out, + int *count, + int max_str_len +) { + char *str = NULL; + if (load_env_str(env_name, &str, 0)) return -1; + + *count = 1 + for (char *p = str; *p; p++) + if (*p == ',') (*count)++; + + for (char *start = str, *p = str; ; p++) { + if (*p == ',' || *p == '\0') { + if ((int)(p - start) > max_str_len) { + log_error("'%.*s' in %s exceeds max length (%d)", + (int)(p - start), start, env_name, max_str_len); + free(str); + return -1; + } + + if (*p == '\0') break; + start = p + 1; + } + } + + char **arr = malloc(*count * sizeof(char *)); + if (!arr) { log_error("Memory allocation failed"); free(str); return -1; } + + int i = 0 + char *token = strtok(str, ","); + while (token) { + arr[i++] = strdup(token); + token = strtok(NULL, ","); + } + + free(str); + *out = arr; + return 0; +} + +int config_load(Config *cfg) { + if (load_env_str(ENV_GANDI_TOKEN, &cfg->api_token, 1)) return -1; + + if (load_env_str(ENV_DNS_KEEPER_DOMAIN, &cfg->dns_keeper_domain, 0)) return -1; + if (load_env_str(ENV_DNS_KEEPER_RECORD, &cfg->dns_keeper_record, 0)) return -1; + if (strlen(cfg->dns_keeper_record) + 1 + strlen(cfg->dns_keeper_domain) > CONFIG_MAX_DOMAIN_LEN) { + log_error("%s.%s exceeds max FQDN length (%d)", + ENV_SELF_RECORD, ENV_SELF_DOMAIN, CONFIG_MAX_FQDN_LEN); + return -1; + } + + if (load_env_int(ENV_DNS_KEEPER_PORT, &cfg->dns_keeper_port, + 1, 65535, DEFAULT_DNS_KEEPER_PORT)) return -1; + if (load_env_int(ENV_POLL_INTERVAL, &cfg->poll_interval, + 1, INT_MAX, DEFAULT_POLL_INTERVAL)) return -1; + + if (load_env_strs(ENV_DOMAINS, &cfg->domains, &cfg->domain_count, CONFIG_MAX_DOMAIN_LEN)) return -1; + + return 0; +} + +void config_free(Config *cfg) { + if (cfg->domains) { + for (int i = 0; i < cfg->domain_count; i++) { + free(cfg->domains[i]); + } + free(cfg->domains); + cfg->domains = NULL; + cfg->domain_count = 0; + } +} \ No newline at end of file diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..a30e146 --- /dev/null +++ b/src/config.h @@ -0,0 +1,28 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#define ENV_GANDI_TOKEN "GANDI_API_TOKEN" +#define ENV_DOMAINS "DOMAINS" +#define ENV_DNS_KEEPER_PORT "DNS_KEEPER_PORT" +#define ENV_DNS_KEEPER_DOMAIN "DNS_KEEPER_DOMAIN" +#define ENV_DNS_KEEPER_RECORD "DNS_KEEPER_RECORD" +#define ENV_POLL_INTERVAL "POLL_INTERVAL" + +#define DEFAULT_DNS_KEEPER_PORT 65535u +#define DEFAULT_POLL_INTERVAL 5u +#define CONFIG_MAX_DOMAIN_LEN 253u /* RFC 1035 max FQDN length */ + +typedef struct { + char *api_token; + char *dns_keeper_domain; + char *dns_keeper_record; + int dns_keeper_port; + int poll_interval; + char **domains; + int domain_count; +} Config; + +int config_load(Config *cfg); +void config_free(Config *cfg); + +#endif /* CONFIG_H */