Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ebec053d2c | |||
| 61cd3a3b4f |
+120
@@ -0,0 +1,120 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 */
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#include "log.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
void log_init(void) {
|
||||||
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ts(char *out, size_t out_sz) {
|
||||||
|
time_t now = time(NULL);
|
||||||
|
struct tm tm;
|
||||||
|
localtime_r(&now, &tm);
|
||||||
|
strftime(out, out_sz, "%Y-%m-%d %H:%M:%S", &tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vlog(FILE *f, const char *level, const char *fmt, va_list ap) {
|
||||||
|
char t[32];
|
||||||
|
ts(t, sizeof(t));
|
||||||
|
fprintf(f, "%s %s: ", t, level);
|
||||||
|
vfprintf(f, fmt, ap);
|
||||||
|
fputc('\n', f);
|
||||||
|
fflush(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_info(const char *fmt, ...) {
|
||||||
|
va_list ap; va_start(ap, fmt);
|
||||||
|
vlog(stdout, "INFO", fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
void log_warn(const char *fmt, ...) {
|
||||||
|
va_list ap; va_start(ap, fmt);
|
||||||
|
vlog(stderr, "WARN", fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
void log_error(const char *fmt, ...) {
|
||||||
|
va_list ap; va_start(ap, fmt);
|
||||||
|
vlog(stderr, "ERROR", fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user