]> git.ipfire.org Git - thirdparty/bird.git/blobdiff - nest/cli.c
Refactoring of net_route
[thirdparty/bird.git] / nest / cli.c
index 30ac75101de188acc0a511fcd270a518b30e6d42..b54a0d76dc26dcaf5cf07bff0b150058a1237061 100644 (file)
  * a continuation line, the whole prefix can be replaced by a single
  * white space character.
  *
- * Reply codes starting with 0 describe `action successfully completed' messages,
+ * Reply codes starting with 0 stand for `action successfully completed' messages,
  * 1 means `table entry', 8 `runtime error' and 9 `syntax error'.
  *
  * Each CLI session is internally represented by a &cli structure and a
  * resource pool containing all resources associated with the connection,
- * so that it can be easily freed whenever the connection closes, not depending
+ * so that it can be easily freed whenever the connection gets closed, not depending
  * on the current state of command processing.
  *
  * The CLI commands are declared as a part of the configuration grammar
- * by using the |CF_CLI| macro. When a command is received, it's processed
+ * by using the |CF_CLI| macro. When a command is received, it is processed
  * by the same lexical analyzer and parser as used for the configuration, but
  * it's switched to a special mode by prepending a fake token to the text,
  * so that it uses only the CLI command rules. Then the parser invokes
  * an execution routine corresponding to the command, which either constructs
- * the whole reply and returns or (in case it expects the reply will be long)
+ * the whole reply and returns it back or (in case it expects the reply will be long)
  * it prints a partial reply and asks the CLI module (using the @cont hook)
- * to call it again when the output will be transferred to the user.
+ * to call it again when the output is transferred to the user.
  *
  * The @this_cli variable points to a &cli structure of the session being
  * currently parsed, but it's of course available only in command handlers
  * not entered using the @cont hook.
+ *
+ * TX buffer management works as follows: At cli.tx_buf there is a
+ * list of TX buffers (struct cli_out), cli.tx_write is the buffer
+ * currently used by the producer (cli_printf(), cli_alloc_out()) and
+ * cli.tx_pos is the buffer currently used by the consumer
+ * (cli_write(), in system dependent code). The producer uses
+ * cli_out.wpos ptr as the current write position and the consumer
+ * uses cli_out.outpos ptr as the current read position. When the
+ * producer produces something, it calls cli_write_trigger(). If there
+ * is not enough space in the current buffer, the producer allocates
+ * the new one. When the consumer processes everything in the buffer
+ * queue, it calls cli_written(), tha frees all buffers (except the
+ * first one) and schedules cli.event .
+ *
  */
 
 #include "nest/bird.h"
@@ -106,11 +120,11 @@ void
 cli_printf(cli *c, int code, char *msg, ...)
 {
   va_list args;
-  byte buf[1024];
+  byte buf[CLI_LINE_SIZE];
   int cd = code;
+  int errcode;
   int size, cnt;
 
-  va_start(args, msg);
   if (cd < 0)
     {
       cd = -cd;
@@ -118,14 +132,27 @@ cli_printf(cli *c, int code, char *msg, ...)
        size = bsprintf(buf, " ");
       else
        size = bsprintf(buf, "%04d-", cd);
+      errcode = -8000;
+    }
+  else if (cd == CLI_ASYNC_CODE)
+    {
+      size = 1; buf[0] = '+';
+      errcode = cd;
     }
   else
-    size = bsprintf(buf, "%04d ", cd);
+    {
+      size = bsprintf(buf, "%04d ", cd);
+      errcode = 8000;
+      cd = 0;  /* Final message - no more continuation lines */
+    }
+
   c->last_reply = cd;
+  va_start(args, msg);
   cnt = bvsnprintf(buf+size, sizeof(buf)-size-1, msg, args);
+  va_end(args);
   if (cnt < 0)
     {
-      cli_printf(c, code < 0 ? -8000 : 8000, "<line overflow>");
+      cli_printf(c, errcode, "<line overflow>");
       return;
     }
   size += cnt;
@@ -137,7 +164,7 @@ static void
 cli_copy_message(cli *c)
 {
   byte *p, *q;
-  unsigned int cnt = 2;
+  uint cnt = 2;
 
   if (c->ring_overflow)
     {
@@ -195,13 +222,21 @@ cli_free_out(cli *c)
   c->async_msg_size = 0;
 }
 
+void
+cli_written(cli *c)
+{
+  cli_free_out(c);
+  ev_schedule(c->event);
+}
+
+
 static byte *cli_rh_pos;
-static unsigned int cli_rh_len;
+static uint cli_rh_len;
 static int cli_rh_trick_flag;
 struct cli *this_cli;
 
 static int
-cli_cmd_read_hook(byte *buf, unsigned int max)
+cli_cmd_read_hook(byte *buf, uint max, UNUSED int fd)
 {
   if (!cli_rh_trick_flag)
     {
@@ -227,6 +262,8 @@ cli_command(struct cli *c)
     log(L_TRACE "CLI: %s", c->rx_buf);
   bzero(&f, sizeof(f));
   f.mem = c->parser_pool;
+  f.pool = rp_new(c->pool, "Config");
+  init_list(&f.symbols);
   cf_read_hook = cli_cmd_read_hook;
   cli_rh_pos = c->rx_buf;
   cli_rh_len = strlen(c->rx_buf);
@@ -236,6 +273,8 @@ cli_command(struct cli *c)
   res = cli_parse(&f);
   if (!res)
     cli_printf(c, 9001, f.err_msg);
+
+  config_free(&f);
 }
 
 static void
@@ -262,11 +301,8 @@ cli_event(void *data)
       else
        cli_command(c);
     }
-  if (cli_write(c))
-    {
-      cli_free_out(c);
-      ev_schedule(c->event);
-    }
+
+  cli_write_trigger(c);
 }
 
 cli *
@@ -282,7 +318,8 @@ cli_new(void *priv)
   c->event->hook = cli_event;
   c->event->data = c;
   c->cont = cli_hello;
-  c->parser_pool = lp_new(c->pool, 4096);
+  c->parser_pool = lp_new_default(c->pool);
+  c->show_pool = lp_new_default(c->pool);
   c->rx_buf = mb_alloc(c->pool, CLI_RX_BUF_SIZE);
   ev_schedule(c->event);
   return c;
@@ -295,18 +332,11 @@ cli_kick(cli *c)
     ev_schedule(c->event);
 }
 
-void
-cli_written(cli *c)
-{
-  cli_free_out(c);
-  ev_schedule(c->event);
-}
-
 static list cli_log_hooks;
 static int cli_log_inited;
 
 void
-cli_set_log_echo(cli *c, unsigned int mask, unsigned int size)
+cli_set_log_echo(cli *c, uint mask, uint size)
 {
   if (c->ring_buf)
     {
@@ -327,7 +357,7 @@ cli_set_log_echo(cli *c, unsigned int mask, unsigned int size)
 }
 
 void
-cli_echo(unsigned int class, byte *msg)
+cli_echo(uint class, byte *msg)
 {
   unsigned len, free, i, l;
   cli *c;
@@ -344,8 +374,8 @@ cli_echo(unsigned int class, byte *msg)
        free = (c->ring_end - c->ring_buf) - (c->ring_write - c->ring_read + 1);
       else
        free = c->ring_read - c->ring_write - 1;
-      if (len > free ||
-         free < c->log_threshold && class < (unsigned) L_INFO[0])
+      if ((len > free) ||
+         (free < c->log_threshold && class < (unsigned) L_INFO[0]))
        {
          c->ring_overflow++;
          continue;
@@ -372,12 +402,17 @@ cli_echo(unsigned int class, byte *msg)
     }
 }
 
+/* Hack for scheduled undo notification */
+extern cli *cmd_reconfig_stored_cli;
+
 void
 cli_free(cli *c)
 {
   cli_set_log_echo(c, 0, 0);
   if (c->cleanup)
     c->cleanup(c);
+  if (c == cmd_reconfig_stored_cli)
+    cmd_reconfig_stored_cli = NULL;
   rfree(c->pool);
 }