From 03e7d06a09986b7877b095bcb1e22a2224b94144 Mon Sep 17 00:00:00 2001
From: Piotr Wydrych <pwydrych@akamai.com>
Date: Mon, 29 Mar 2021 16:10:36 +0200
Subject: [PATCH] MRT: Add overwrite switch (default: off)

Provide ability to turn off appending to the MRT dump file via configuration.
---
 doc/bird.sgml      |  4 ++++
 proto/mrt/config.Y |  3 ++-
 proto/mrt/mrt.c    | 21 ++++++++++++++++++++-
 proto/mrt/mrt.h    |  9 +++++++++
 4 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/doc/bird.sgml b/doc/bird.sgml
index e4ddded2..8301cf4a 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -3326,6 +3326,9 @@ The behavior can be modified by following configuration parameters:
 	of dumped table. Therefore, each periodic dump of each table can be
 	saved to a different file. Mandatory, see example below.
 
+	<tag><label id="mrt-overwrite">overwrite <m/switch/</tag>
+	Truncate the MRT dump file(s) on open. Default: disabled.
+
 	<tag><label id="mrt-period">period <m/number/</tag>
 	Specify the time interval (in seconds) between periodic dumps.
 	Mandatory.
@@ -3348,6 +3351,7 @@ protocol mrt {
 	table "tab*";
 	where source = RTS_BGP;
 	filename "/var/log/bird/%N_%F_%T.mrt";
+	overwrite;
 	period 300;
 }
 </code>
diff --git a/proto/mrt/config.Y b/proto/mrt/config.Y
index 4da6777a..67501caf 100644
--- a/proto/mrt/config.Y
+++ b/proto/mrt/config.Y
@@ -17,7 +17,7 @@ CF_DEFINES
 
 CF_DECLS
 
-CF_KEYWORDS(MRT, TABLE, FILTER, FILENAME, PERIOD, ALWAYS, ADD, PATH, DUMP, TO)
+CF_KEYWORDS(MRT, TABLE, FILTER, FILENAME, PERIOD, ALWAYS, ADD, PATH, DUMP, TO, OVERWRITE)
 
 %type <md> mrt_dump_args
 
@@ -37,6 +37,7 @@ mrt_proto_item:
  | FILTER filter	{ MRT_CFG->filter = $2; }
  | where_filter		{ MRT_CFG->filter = $1; }
  | FILENAME text	{ MRT_CFG->filename = $2; }
+ | OVERWRITE bool	{ MRT_CFG->overwrite = $2; }
  | PERIOD expr		{ MRT_CFG->period = $2; }
  | ALWAYS ADD PATH bool	{ MRT_CFG->always_add_path = $4; }
  ;
diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c
index 838360c2..e08802f9 100644
--- a/proto/mrt/mrt.c
+++ b/proto/mrt/mrt.c
@@ -258,6 +258,8 @@ mrt_open_file(struct mrt_table_dump_state *s)
   char name[BIRD_PATH_MAX];
   btime now = current_time();
   btime now_real = current_real_time();
+  struct mrt_overwritten_file_entry *f;
+  int overwrite = s->overwrite;
 
   if (!bstrsub(fmt1, sizeof(fmt1), s->filename, "%N", s->table->name) ||
       !tm_format_real_time(name, sizeof(name), fmt1, now_real))
@@ -266,12 +268,26 @@ mrt_open_file(struct mrt_table_dump_state *s)
     return 0;
   }
 
-  s->file = rf_open(s->pool, name, "a");
+  if (overwrite)
+    WALK_LIST(f, s->overwritten_files)
+      if (!bstrcmp(name, f->filename))
+      {
+        /* already overwrote this particular file in this dump run */
+        overwrite = 0;
+        break;
+      }
+  s->file = rf_open(s->pool, name, overwrite ? "w" : "a");
   if (!s->file)
   {
     mrt_log(s, "Unable to open MRT file '%s': %m", name);
     return 0;
   }
+  if (overwrite) {
+    f = mb_alloc(s->pool, sizeof(struct mrt_overwritten_file_entry));
+    f->filename = mb_alloc(s->pool, sizeof(name));
+    bmemcpy(f->filename, name, sizeof(name));
+    add_tail(&s->overwritten_files, &f->n);
+  }
 
   s->fd = rf_fileno(s->file);
   s->time_offset = now_real - now;
@@ -660,6 +676,9 @@ mrt_timer(timer *t)
   s->table_ptr = cf->table_cf ? cf->table_cf->table : NULL;
   s->filter = cf->filter;
   s->filename = cf->filename;
+  s->overwrite = cf->overwrite;
+  if (s->overwrite)
+    init_list(&s->overwritten_files);
   s->always_add_path = cf->always_add_path;
 
   if (s->table_ptr)
diff --git a/proto/mrt/mrt.h b/proto/mrt/mrt.h
index 4ff94c12..aeb7cc3d 100644
--- a/proto/mrt/mrt.h
+++ b/proto/mrt/mrt.h
@@ -25,6 +25,7 @@ struct mrt_config {
   const char *table_expr;
   const struct filter *filter;
   const char *filename;
+  int overwrite;
   uint period;
   int always_add_path;
 };
@@ -53,6 +54,12 @@ struct mrt_peer_entry {
   struct mrt_peer_entry *next;
 };
 
+/* to keep track of files that were open in current dump if overwrite is requested */
+struct mrt_overwritten_file_entry {
+  node n;
+  char *filename;
+};
+
 struct mrt_table_dump_state {
   struct mrt_proto *proto;		/* Protocol for regular MRT dumps (or NULL) */
   struct cli *cli;			/* CLI for irregular MRT dumps (or NULL) */
@@ -63,6 +70,7 @@ struct mrt_table_dump_state {
   struct rtable *table_ptr;		/* Explicit table (or NULL) */
   const struct filter *filter;		/* Optional filter */
   const char *filename;			/* Filename pattern */
+  int overwrite;			/* Append to file */
   int always_add_path;			/* Always use *_ADDPATH message subtypes */
 
   /* Allocated by mrt_table_dump_init() */
@@ -91,6 +99,7 @@ struct mrt_table_dump_state {
   u32 entry_count_offset;		/* Buffer offset to store entry_count later */
 
   struct rfile *file;			/* tracking for mrt table dump file */
+  list overwritten_files;		/* used only if overwrite - keep track of already overwritten files */
   int fd;
 };
 
-- 
2.24.3 (Apple Git-128)

