Further update. Do not write to the file the states of dynamic protocols as
it does not have much sence.

On Fri, Jan 27, 2023 at 2:53 AM Alexander Zubkov <gr...@qrator.net> wrote:

> Updated the patch for keeping state in the file. Moved the read/write
> functions to sysdep/unix/main.c and made better parsing. So it is not a
> draft anymore, but something more or less "stable". I can add documentation
> patch in case there is interest to include that into upstream.
>
> On Tue, Jan 24, 2023 at 8:03 AM Ondrej Zajicek <santi...@crfreenet.org>
> wrote:
>
>> On Mon, Jan 23, 2023 at 03:19:43AM +0100, Alexander Zubkov wrote:
>> > Hello,
>> >
>> > Not sure if those are forgotten or are unwanted modifications. Please
>> let
>> > me know.
>> >
>> > And I also have another idea regarding the subject. The idea is to
>> > configure the file where bird will keep the states of the protocols (I
>> mean
>> > enabled/disabled states). Then during loading the configuration it
>> alters
>> > the states to reflect the saved ones. So the states are persistent
>> during
>> > reconfiguration and also during restart of a daemon. The draft patch is
>> > attached. Please take a look.
>>
>> Hello
>>
>> Forgot about it, will check it.
>>
>> --
>> Elen sila lumenn' omentielvo
>>
>> Ondrej 'Santiago' Zajicek (email: santi...@crfreenet.org)
>> OpenPGP encrypted e-mails preferred (KeyID 0x11DEADC3, wwwkeys.pgp.net)
>> "To err is human -- to blame it on a computer is even more so."
>>
>
commit 51272e90d6867a0a5604e13d7b1d6388249e89ef
Author: Alexander Zubkov <gr...@qrator.net>
Date:   Sun Jan 29 11:39:56 2023 +0100

    Config: define file for keeping persistent protocol states
    
    Persist protocols enabled/disabled states by keeping them in a file, if
    its name is defined in the config file. Upon loading the config file
    the states of the protocols are updated according to the file. The file
    is rewritten when some protocol is enabled/disabled by CLI. The state of
    dynamic protocols is not saved.

diff --git a/conf/conf.c b/conf/conf.c
index 4e31de29..da42a78a 100644
--- a/conf/conf.c
+++ b/conf/conf.c
@@ -287,6 +287,8 @@ config_do_commit(struct config *c, int type)
   if (old_config)
     old_config->obstacle_count++;
 
+  DBG("proto_states_read\n");
+  proto_states_read(c);
   DBG("filter_commit\n");
   filter_commit(c, old_config);
   DBG("sysdep_commit\n");
diff --git a/conf/conf.h b/conf/conf.h
index b409750e..ecbe9408 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -28,6 +28,7 @@ struct config {
 
   int mrtdump_file;			/* Configured MRTDump file (sysdep, fd in unix) */
   const char *syslog_name;		/* Name used for syslog (NULL -> no syslog) */
+  void *states_file;			/* Protocol states file (sysdep, FILE *) */
   struct rtable_config *def_tables[NET_MAX]; /* Default routing tables for each network */
   struct iface_patt *router_id_from;	/* Configured list of router ID iface patterns */
 
diff --git a/nest/proto.c b/nest/proto.c
index 885a0b75..4e70f585 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -21,6 +21,7 @@
 #include "nest/cli.h"
 #include "filter/filter.h"
 #include "filter/f-inst.h"
+#include "sysdep/unix/unix.h"
 
 pool *proto_pool;
 list STATIC_LIST_INIT(proto_list);
@@ -2105,6 +2106,7 @@ proto_cmd_disable(struct proto *p, uintptr_t arg, int cnt UNUSED)
   p->down_code = PDC_CMD_DISABLE;
   proto_set_message(p, (char *) arg, -1);
   proto_rethink_goal(p);
+  proto_states_write(p);
   cli_msg(-9, "%s: disabled", p->name);
 }
 
@@ -2121,6 +2123,7 @@ proto_cmd_enable(struct proto *p, uintptr_t arg, int cnt UNUSED)
   p->disabled = 0;
   proto_set_message(p, (char *) arg, -1);
   proto_rethink_goal(p);
+  proto_states_write(p);
   cli_msg(-11, "%s: enabled", p->name);
 }
 
diff --git a/sysdep/unix/config.Y b/sysdep/unix/config.Y
index 5c4b5bef..cc7813c8 100644
--- a/sysdep/unix/config.Y
+++ b/sysdep/unix/config.Y
@@ -101,6 +101,20 @@ mrtdump_base:
  ;
 
 
+conf: keep_states ;
+
+keep_states: KEEP STATES text ';' {
+    if (!parse_and_exit)
+    {
+      if (new_config->states_file) cf_error("Repeating definition of protocol states file");
+      struct rfile *f = rf_open(new_config->pool, $3, "a+");
+      if (!f) cf_error("Unable to open protocol states file '%s': %m", $3);
+      new_config->states_file = rf_file(f);
+    }
+  }
+;
+
+
 conf: debug_unix ;
 
 debug_unix:
diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c
index 627d7a4a..ba688cdf 100644
--- a/sysdep/unix/main.c
+++ b/sysdep/unix/main.c
@@ -389,6 +389,89 @@ cmd_reconfig_status(void)
   cli_msg(0, "");
 }
 
+/*
+ *	Protocol states reading/writing
+ */
+
+void
+proto_states_read(struct config *c)
+{
+  FILE *f = c->states_file;
+  if (!f) return;
+
+  log(L_INFO "Reading protocol states file");
+
+  /* Move to the start of the file */
+  fseek(f, 0, SEEK_SET);
+  fflush(f);
+
+  const char *fmt = "%" XSTR1(SYM_MAX_LEN) "s %u";
+  char buf[512];
+
+  /* Use longer buffer to check for too long names */
+  char name[SYM_MAX_LEN + 1];
+  uint enabled;
+
+  int longline = 0, line = 0;
+  while (fgets(buf, sizeof(buf), f))
+  {
+    int len = strlen(buf);
+    int eol = len && buf[len - 1] == '\n';
+
+    /* Skip long line tail */
+    if (longline)
+    {
+      if (eol) longline = 0;
+      continue;
+    }
+
+    ++line;
+    if (!eol) longline = 1;
+
+    if (sscanf(buf, fmt, name, &enabled) != 2 || strlen(name) >= SYM_MAX_LEN)
+    {
+      log(L_ERR "Format error in states file on line %d", line);
+      continue;
+    }
+
+    struct symbol *sym = cf_find_symbol(c, name);
+    if (sym && sym->class == SYM_PROTO)
+    {
+      struct proto_config *pc = sym->proto;
+      log(L_INFO "Applying state to protocol %s: %d", pc->name, enabled);
+      pc->disabled = !enabled;
+    }
+  }
+}
+
+void
+proto_states_write(struct proto *proto_changed)
+{
+  /* Ignore dynamic protocols */
+  if (proto_changed->cf->parent)
+    return;
+
+  FILE *f = proto_changed->cf->global->states_file;
+  if (!f) return;
+
+  log(L_INFO "Rewriting protocol states file");
+
+  /* Move to the start and truncate the file for rewriting */
+  fseek(f, 0, SEEK_SET);
+  fflush(f);
+  ftruncate(fileno(f), 0);
+
+  struct proto *p;
+  WALK_LIST(p, proto_list)
+  {
+    /* Ignore dynamic protocols */
+    if (!p->cf->parent)
+      fprintf(f, "%s %d\n", p->name, !p->disabled);
+  }
+
+  fflush(f);
+}
+
 
 /*
  *	Command-Line Interface
diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h
index ad85d1ea..ea69914b 100644
--- a/sysdep/unix/unix.h
+++ b/sysdep/unix/unix.h
@@ -16,6 +16,8 @@ struct pool;
 struct iface;
 struct birdsock;
 struct rfile;
+struct config;
+struct proto;
 
 /* main.c */
 
@@ -33,6 +35,9 @@ void cmd_reconfig_status(void);
 void cmd_shutdown(void);
 void cmd_graceful_restart(void);
 
+void proto_states_read(struct config *c);
+void proto_states_write(struct proto *proto_changed);
+
 #define UNIX_DEFAULT_CONFIGURE_TIMEOUT	300
 
 #define UNIX_DEFAULT_LATENCY_LIMIT	(1 S_)

Reply via email to