From 4fc344ac6ed4d7355ad24e35355c280ce42cd300 Mon Sep 17 00:00:00 2001
From: Anjan Chanda <anjan.chanda@iopsys.eu>
Date: Tue, 15 Aug 2023 13:20:42 +0200
Subject: [PATCH] support reboot persistent hosts history

---
 src/config.c   | 18 ++++++++++++++++++
 src/hostmngr.c |  2 +-
 src/hostmngr.h |  2 ++
 3 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/src/config.c b/src/config.c
index 0dd17d3..61e55d4 100644
--- a/src/config.c
+++ b/src/config.c
@@ -11,6 +11,8 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/statfs.h>
+#include <linux/magic.h>
 
 #include <json-c/json.h>
 #include <libubox/blobmsg.h>
@@ -57,6 +59,7 @@ static int hostmngr_config_get_base(struct hostmngr_config *cfg, struct uci_sect
 	enum {
 		HOSTMNGR_ENABLE,
 		HOSTMNGR_HISTORY,
+		HOSTMNGR_HISTORY_PERSIST_REBOOT,
 		HOSTMNGR_HISTORY_FILE,
 		HOSTMNGR_HISTORY_TIMEOUT,
 		HOSTMNGR_HISTORY_MAX_NUM,
@@ -66,6 +69,7 @@ static int hostmngr_config_get_base(struct hostmngr_config *cfg, struct uci_sect
 	const struct uci_parse_option opts[] = {
 		{ .name = "enabled", .type = UCI_TYPE_STRING },
 		{ .name = "history", .type = UCI_TYPE_STRING },
+		{ .name = "history_reboot_persistent", .type = UCI_TYPE_STRING },
 		{ .name = "history_file", .type = UCI_TYPE_STRING },
 		{ .name = "history_timeout", .type = UCI_TYPE_STRING },
 		{ .name = "history_max_entries", .type = UCI_TYPE_STRING },
@@ -88,6 +92,12 @@ static int hostmngr_config_get_base(struct hostmngr_config *cfg, struct uci_sect
 		cfg->history = atoi(val) == 1 ? true : false;
 	}
 
+	if (tb[HOSTMNGR_HISTORY_PERSIST_REBOOT]) {
+		char *val = tb[HOSTMNGR_HISTORY_PERSIST_REBOOT]->v.string;
+
+		cfg->history_persist = atoi(val) == 1 ? true : false;
+	}
+
 	if (tb[HOSTMNGR_HISTORY_TIMEOUT]) {
 		char *val = tb[HOSTMNGR_HISTORY_TIMEOUT]->v.string;
 		int tmo = atoi(val);
@@ -107,6 +117,12 @@ static int hostmngr_config_get_base(struct hostmngr_config *cfg, struct uci_sect
 		}
 	}
 
+	/* point history file to tmpfs if reboot persistence is not desired */
+	if (!cfg->history_persist) {
+		memset(cfg->history_file, 0, sizeof(cfg->history_file));
+		strcpy(cfg->history_file, DEFAULT_HISTORY_TMPFS_FILE);
+	}
+
 	if (tb[HOSTMNGR_HISTORY_MAX_NUM]) {
 		const char *val = tb[HOSTMNGR_HISTORY_MAX_NUM]->v.string;
 		int num = atoi(val);
@@ -228,6 +244,7 @@ int hostmngr_config_defaults(struct hostmngr_config *cfg)
 {
 	cfg->enabled = true;
 	cfg->history = true;
+	cfg->history_persist = true;
 	cfg->stats = true;
 	strcpy(cfg->history_file, DEFAULT_HISTORY_FILE);
 	cfg->history_ageout = DEFAULT_HISTORY_AGEOUT;
@@ -253,6 +270,7 @@ int hostmngr_dump_config(struct hostmngr_config *cfg)
 	fprintf(stderr, " Enabled           : %d\n", cfg->enabled);
 	fprintf(stderr, " Collect stats     : %d\n", cfg->stats);
 	fprintf(stderr, " History           : %d\n", cfg->history);
+	fprintf(stderr, " History persists  : %d\n", cfg->history_persist);
 	fprintf(stderr, " History file      : %s\n", cfg->history_file);
 	fprintf(stderr, " History maxnum    : %u\n", cfg->history_maxnum);
 	fprintf(stderr, " History maxsize   : %u\n", cfg->history_maxsize);
diff --git a/src/hostmngr.c b/src/hostmngr.c
index c558741..9dab5e5 100644
--- a/src/hostmngr.c
+++ b/src/hostmngr.c
@@ -735,7 +735,7 @@ int hostmngr_init_private(struct hostmngr_private *priv, void *useropts)
 
 	neigh_queue_init(&priv->neigh_q);
 
-	if (priv->cfg.history)
+	if (priv->cfg.history && priv->cfg.history_persist)
 		neigh_history_load_from_json_file(priv, priv->cfg.history_file);
 
 	hostmngr_get_interface_neighbors(priv);
diff --git a/src/hostmngr.h b/src/hostmngr.h
index dc70ceb..f5b6952 100644
--- a/src/hostmngr.h
+++ b/src/hostmngr.h
@@ -156,6 +156,7 @@ struct node_interface {
 };
 
 #define DEFAULT_HISTORY_FILE            "/etc/hosts_history.json"
+#define DEFAULT_HISTORY_TMPFS_FILE      "/tmp/hosts_history.json"
 #define DEFAULT_HISTORY_AGEOUT          604800		/* 7 days in seconds */
 #define DEFAULT_HISTORY_MAX_NUM         512
 #define DEFAULT_HISTORY_MAX_SIZE        0x100000	/* 1Mb */
@@ -165,6 +166,7 @@ struct hostmngr_config {
 	const char *objname;
 	bool enabled;
 	bool history;			/* keep history */
+	bool history_persist;		/* keep history across reboot */
 	bool stats;			/* gather stats */
 	bool update_config;
 	int num_ifnames;
-- 
GitLab