aboutsummaryrefslogtreecommitdiffstats
path: root/src/pingu_conf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pingu_conf.c')
-rw-r--r--src/pingu_conf.c253
1 files changed, 253 insertions, 0 deletions
diff --git a/src/pingu_conf.c b/src/pingu_conf.c
new file mode 100644
index 0000000..263a1f4
--- /dev/null
+++ b/src/pingu_conf.c
@@ -0,0 +1,253 @@
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+#include "pingu_iface.h"
+#include "pingu_host.h"
+#include "xlib.h"
+
+struct pingu_conf {
+ const char *filename;
+ FILE *fh;
+ int lineno;
+};
+
+static float default_burst_interval = 30.0;
+static float default_timeout = 1.0;
+static int default_max_retries = 5;
+static int default_required_replies = 3;
+static char *default_up_action = NULL;
+static char *default_down_action = NULL;
+
+/* note: this overwrite the line buffer */
+static void parse_line(char *line, char **key, char **value)
+{
+ char *p;
+
+ (*value) = NULL;
+ (*key) = NULL;
+
+ /* strip comments and trailing \n */
+ p = strpbrk(line, "#\n");
+ if (p)
+ *p = '\0';
+
+ /* skip leading whitespace */
+ while (isspace(*line))
+ line++;
+ if (*line == '\0')
+ return;
+
+ (*key) = line;
+
+ /* find space between keyword and value */
+ p = line;
+ while (!isspace(*p)) {
+ if (*p == '\0')
+ return;
+ p++;
+ }
+ *p++ = '\0';
+
+ /* find value */
+ while (isspace(*p))
+ p++;
+ if (*p == '\0')
+ return;
+
+ (*value) = p;
+}
+
+static struct pingu_conf *pingu_conf_open(const char *filename)
+{
+ struct pingu_conf *f = calloc(1, sizeof(struct pingu_conf));
+ if (f == NULL) {
+ log_perror("calloc");
+ return NULL;
+ }
+ f->fh = fopen(filename, "r");
+ if (f->fh == NULL) {
+ log_perror(filename);
+ free(f);
+ return NULL;
+ }
+ f->filename = filename;
+ return f;
+}
+
+static void pingu_conf_close(struct pingu_conf *f)
+{
+ fclose(f->fh);
+ free(f);
+}
+
+static char *chomp_bracket(char *str)
+{
+ char *p = str;
+ /* chomp */
+ while (!isspace(*p))
+ p++;
+ *p = '\0';
+ return str;
+}
+
+static char *pingu_conf_read_key_value(struct pingu_conf *conf, char **key,
+ char **value)
+{
+ static char line[1024];
+ char *k = NULL, *v = NULL;
+ while (k == NULL || *k == '\0') {
+ if (fgets(line, sizeof(line), conf->fh) == NULL)
+ return NULL;
+ conf->lineno++;
+ parse_line(line, &k, &v);
+ }
+ *key = k;
+ *value = v;
+ return line;
+}
+
+static struct pingu_host *pingu_conf_new_host(const char *hoststr)
+{
+ return pingu_host_new(xstrdup(hoststr), default_burst_interval,
+ default_max_retries, default_required_replies,
+ default_timeout, default_up_action,
+ default_down_action);
+}
+
+static int pingu_conf_read_iface(struct pingu_conf *conf, char *ifname)
+{
+ struct pingu_iface *iface;
+ char *key, *value;
+
+ iface = pingu_iface_get_by_name(ifname);
+ if (iface != NULL) {
+ log_error("Interface %s already declared (line %i)", conf->lineno);
+ return -1;
+ }
+
+ iface = pingu_iface_get_by_name_or_new(ifname);
+ if (iface == NULL)
+ return -1;
+
+ while (pingu_conf_read_key_value(conf, &key, &value)) {
+ if (key == NULL || key[0] == '}')
+ break;
+ if (strcmp(key, "route-table") == 0) {
+ pingu_iface_set_route_table(iface, atoi(value));
+ } else if (strcmp(key, "label") == 0) {
+ iface->label = xstrdup(value);
+ } else if (strcmp(key, "gateway-up-action") == 0) {
+ iface->gw_up_action = xstrdup(value);
+ } else if (strcmp(key, "gateway-down-action") == 0) {
+ iface->gw_down_action = xstrdup(value);
+ } else if (strcmp(key, "required-hosts-online") == 0) {
+ iface->required_hosts_online = atoi(value);
+ } else if (strcmp(key, "rule-priority") == 0) {
+ iface->rule_priority = atoi(value);
+ } else if (strcmp(key, "load-balance") == 0) {
+ int weight = 0;
+ if (value != NULL) {
+ weight = atoi(value);
+ if (weight <= 0 || weight > 256) {
+ log_error("Invalid load-balance weight %i on line %i",
+ weight, conf->lineno);
+ return -1;
+ }
+ }
+ pingu_iface_set_balance(iface, weight);
+ } else if (strcmp(key, "ping") == 0) {
+ struct pingu_host *host = pingu_conf_new_host(value);
+ host->iface = iface;
+ } else if (strcmp(key, "fwmark") == 0) {
+ iface->fwmark = atoi(value);
+ } else {
+ log_error("Unknown keyword '%s' on line %i", key,
+ conf->lineno);
+ }
+ }
+ return 0;
+}
+
+static int pingu_conf_read_host(struct pingu_conf *conf, char *hoststr)
+{
+ char *key, *value;
+ struct pingu_host *host = pingu_conf_new_host(hoststr);
+
+ while (pingu_conf_read_key_value(conf, &key, &value)) {
+ if (key == NULL || key[0] == '}')
+ break;
+ if (strcmp(key, "bind-interface") == 0) {
+ host->iface = pingu_iface_get_by_name_or_new(value);
+ if (host->iface == NULL) {
+ log_error("Undefined interface %s on line %i",
+ value, conf->lineno);
+ return -1;
+ }
+ } else if (strcmp(key, "label") == 0) {
+ host->label = xstrdup(value);
+ } else if (strcmp(key, "up-action") == 0) {
+ host->up_action = xstrdup(value);
+ } else if (strcmp(key, "down-action") == 0) {
+ host->down_action = xstrdup(value);
+ } else if (strcmp(key, "retry") == 0) {
+ host->max_retries = atoi(value);
+ } else if (strcmp(key, "required") == 0) {
+ host->required_replies = atoi(value);
+ } else if (strcmp(key, "timeout") == 0) {
+ host->timeout = atof(value);
+ } else if (strcmp(key, "interval") == 0) {
+ host->burst_interval = atof(value);
+ } else {
+ log_error("Unknown keyword '%s' on line %i", key,
+ conf->lineno);
+ }
+ }
+ if (host->iface == NULL)
+ host->iface = pingu_iface_get_by_name_or_new(NULL);
+ return 0;
+}
+
+int pingu_conf_parse(const char *filename)
+{
+ int r = 0;
+ char *key, *value;
+ struct pingu_conf *conf = pingu_conf_open(filename);
+
+ if (conf == NULL)
+ return -1;
+
+ while (pingu_conf_read_key_value(conf, &key, &value)) {
+ if (strcmp(key, "interface") == 0) {
+ r = pingu_conf_read_iface(conf, chomp_bracket(value));
+ if (r < 0)
+ break;
+ } else if (strcmp(key, "host") == 0) {
+ r = pingu_conf_read_host(conf, chomp_bracket(value));
+ if (r < 0)
+ break;
+ } else if (strcmp(key, "interval") == 0) {
+ default_burst_interval = atof(value);
+ } else if (strcmp(key, "retry") == 0) {
+ default_max_retries = atoi(value);
+ } else if (strcmp(key, "required") == 0) {
+ default_required_replies = atoi(value);
+ } else if (strcmp(key, "timeout") == 0) {
+ default_timeout = atof(value);
+ } else if (strcmp(key, "up-action") == 0) {
+ default_up_action = xstrdup(value);
+ } else if (strcmp(key, "down-action") == 0) {
+ default_down_action = xstrdup(value);
+ } else {
+ log_error("Unknown keyword '%s' on line %i", key,
+ conf->lineno);
+ r = -1;
+ break;
+ }
+ }
+ pingu_conf_close(conf);
+ return r;
+}