[PATCH] Client: add "show hostname" command, and add client prompt hostname display

Molly Miller bird at m-squa.red
Thu Feb 11 22:14:23 CET 2021


Hi all,

The recent patch on the list from Vincent Bernat which added support for the
draft BGP hostname capability [1] reminded me of a thread from last year, in
which there was a feature request for the ability to display the system
hostname in the Bird client prompt [2].

This feature doesn't appear to have been implemented since then, and now
that a hostname is tracked internally by Bird, I've written a 
proof-of-concept patch (appended inline) which displays the daemon hostname
in the client prompt.

This patch adds a "show hostname" command to the daemon for convenience, and
modifies the client to automatically issue this command when starting in
interactive mode. The client then intercepts the response (which will either
contain the daemon hostname, or be a syntax error if the daemon does not
understand the command), and then sets the received hostname in the prompt
if the response is a success code.

(The rationale for not simply calling uname(2) in the client is that the
resulting nodename may not match the hostname configured in the daemon, in
the case where the daemon configuration contains a hostname "<foo>"
directive. It's also possible to connect to the daemon over a Unix socket
forwarded over SSH, in which case the client would be running on a separate
system with a different hostname regardless of the daemon configuration --
thanks to Tim Stallard for pointing this out.)

I don't know how willing the Bird maintainers would be to commit this patch,
however I thought I'd post it to the list in case anyone else is interested.

Cheers,
--mm.


[1]: https://bird.network.cz/pipermail/bird-users/2021-February/015187.html,
merged as 71423871
[2]: https://bird.network.cz/pipermail/bird-users/2020-July/014678.html


-- >8 --
Subject: [PATCH] Client: add "show hostname" command, and client prompt
 hostname display.

This patch adds a "show hostname" command to the daemon, which returns the
server's currently configured hostname, and extends the command line client
to issue this command upon connecting to the daemon, in order to retrieve a
hostname to display in the client's prompt. A '-p' option has also been added
to suppress this behaviour.

    molly on flywheel ~> birdc
    BIRD v2.0.7 ready.
    bird (flywheel)> show hostname
    Hostname: flywheel
    bird (flywheel)> exit

    molly on flywheel ~> birdc -p
    BIRD v2.0.7 ready.
    bird> show hostname
    Hostname: flywheel
    bird> quit

Additionally, the error message generated by older versions of the daemon when
running the "show hostname" command is caught, in order to remain interoperable
with versions which do not have this patch.

The client program does not, however, have any means of detecting whether the
hostname changes as part of an online configuration update, so changes in the
daemon's hostname will not be propagated to a client which is persistent across
the configuration change.
---
 client/birdc.c  | 11 +++++++++--
 client/birdcl.c |  8 +++++++-
 client/client.c | 48 ++++++++++++++++++++++++++++++++++++++++++------
 client/client.h |  2 ++
 doc/reply_codes |  1 +
 nest/cmds.c     |  7 +++++++
 nest/cmds.h     |  1 +
 nest/config.Y   |  3 +++
 8 files changed, 72 insertions(+), 9 deletions(-)

diff --git a/client/birdc.c b/client/birdc.c
index f1aea2fe..b1b9b218 100644
--- a/client/birdc.c
+++ b/client/birdc.c
@@ -162,7 +162,7 @@ input_init(void)
   rl_readline_name = "birdc";
   rl_add_defun("bird-complete", input_complete, '\t');
   rl_add_defun("bird-help", input_help, '?');
-  rl_callback_handler_install("bird> ", input_got_line);
+  rl_callback_handler_install(prompt_string, input_got_line);
 
   // rl_get_screen_size();
   term_lns = LINES;
@@ -184,7 +184,7 @@ input_reveal(void)
   tcdrain(STDOUT_FILENO);
 
   rl_end = input_hidden_end;
-  rl_expand_prompt("bird> ");
+  rl_expand_prompt(prompt_string);
   rl_forced_update_display();
 
   prompt_active = 1;
@@ -201,6 +201,13 @@ input_hide(void)
   prompt_active = 0;
 }
 
+void
+input_reload(void)
+{
+  input_hide();
+  input_reveal();
+}
+
 void
 input_notify(int prompt)
 {
diff --git a/client/birdcl.c b/client/birdcl.c
index 4508185c..d36914c9 100644
--- a/client/birdcl.c
+++ b/client/birdcl.c
@@ -38,6 +38,12 @@ input_stop_list(void)
   /* Empty in non-ncurses version. */
 }
 
+void
+input_reload(void)
+{
+  /* Empty in non-ncurses version. */
+}
+
 void
 input_notify(int prompt)
 {
@@ -45,7 +51,7 @@ input_notify(int prompt)
   if (!prompt)
     return;
 
-  printf("bird> ");
+  printf(prompt_string);
   fflush(stdout);
 }
 
diff --git a/client/client.c b/client/client.c
index 97cf6639..0de7aaaf 100644
--- a/client/client.c
+++ b/client/client.c
@@ -37,8 +37,11 @@
 #include "sysdep/unix/unix.h"
 
 #define SERVER_READ_BUF_LEN 4096
+#define SERVER_PROMPT_LEN 64
+#define SERVER_PROMPT_DEFAULT "bird> "
+#define SERVER_HOSTNAME_PREFIX "Hostname: "
 
-static char *opt_list = "s:vrl";
+static char *opt_list = "s:vrlp";
 static int verbose, restricted, once;
 static char *init_cmd;
 
@@ -47,12 +50,15 @@ static int server_fd;
 static byte server_read_buf[SERVER_READ_BUF_LEN];
 static byte *server_read_pos = server_read_buf;
 
-int init = 1;		/* During intial sequence */
-int busy = 1;		/* Executing BIRD command */
-int interactive;	/* Whether stdin is terminal */
+int init = 1;				/* During intial sequence */
+int busy = 1;				/* Executing BIRD command */
+int hostprompt = 1;			/* Whether to show hostname in prompt */
+int interactive;			/* Whether stdin is terminal */
+char prompt_string[SERVER_PROMPT_LEN];	/* Prompt string */
 
 static int num_lines, skip_input;
 int term_lns, term_cls;
+static int hostname_read = 0;
 
 
 /*** Parsing of arguments ***/
@@ -60,7 +66,7 @@ int term_lns, term_cls;
 static void
 usage(char *name)
 {
-  fprintf(stderr, "Usage: %s [-s <control-socket>] [-v] [-r] [-l]\n", name);
+  fprintf(stderr, "Usage: %s [-s <control-socket>] [-v] [-r] [-l] [-p]\n", name);
   exit(1);
 }
 
@@ -87,6 +93,9 @@ parse_args(int argc, char **argv)
 	if (!server_changed)
 	  server_path = xbasename(server_path);
 	break;
+      case 'p':
+	hostprompt = 0;
+	break;
       default:
 	usage(argv[0]);
       }
@@ -199,6 +208,12 @@ init_commands(void)
       exit(0);
     }
 
+  /* Set up local prompt, and attempt to retrieve daemon hostname */
+  memset(prompt_string, 0, sizeof(prompt_string));
+  strcpy(prompt_string, SERVER_PROMPT_DEFAULT);
+  if (hostprompt)
+    submit_server_command("show hostname");
+
   input_init();
 
   term_lns = (term_lns > 0) ? term_lns : 25;
@@ -239,6 +254,16 @@ more(void)
   more_end();
 }
 
+static void
+update_prompt(char *x)
+{
+  if (strncmp(x, SERVER_HOSTNAME_PREFIX, sizeof(SERVER_HOSTNAME_PREFIX)-1) != 0)
+    return;
+
+  memset(prompt_string, 0, sizeof(prompt_string));
+  snprintf(prompt_string, sizeof(prompt_string), "bird (%s)> ", x+sizeof(SERVER_HOSTNAME_PREFIX)-1);
+}
+
 
 /*** Communication with server ***/
 
@@ -281,7 +306,18 @@ server_got_reply(char *x)
            (x[4] == ' ' || x[4] == '-'))
     {
       if (code)
-        PRINTF(len, "%s\n", verbose ? x : x+5);
+      {
+        if ((code == 1026 || code == 9001) && !hostname_read && hostprompt)
+        {
+          hostname_read = 1;
+          if (code == 1026) {
+            update_prompt(x+5);
+            input_reload();
+          }
+        }
+        else
+          PRINTF(len, "%s\n", verbose ? x : x+5);
+      }
 
       if (x[4] == ' ')
       {
diff --git a/client/client.h b/client/client.h
index f9693def..8de7b38c 100644
--- a/client/client.h
+++ b/client/client.h
@@ -9,6 +9,7 @@
 
 extern int init, busy, interactive;
 extern int term_lns, term_cls;
+extern char prompt_string[];
 
 /* birdc.c / birdcl.c */
 
@@ -16,6 +17,7 @@ void input_start_list(void);
 void input_stop_list(void);
 
 void input_init(void);
+void input_reload(void);
 void input_notify(int prompt);
 void input_read(void);
 
diff --git a/doc/reply_codes b/doc/reply_codes
index 02f4e656..47f9d3e8 100644
--- a/doc/reply_codes
+++ b/doc/reply_codes
@@ -61,6 +61,7 @@ Reply codes of BIRD command-line interface
 1023	Show Babel interfaces
 1024	Show Babel neighbors
 1025	Show Babel entries
+1026	Show hostname
 
 8000	Reply too long
 8001	Route not found
diff --git a/nest/cmds.c b/nest/cmds.c
index 18f39eb5..a412faf3 100644
--- a/nest/cmds.c
+++ b/nest/cmds.c
@@ -95,6 +95,13 @@ cmd_show_memory(void)
   cli_msg(0, "");
 }
 
+void
+cmd_show_hostname(void)
+{
+  cli_msg(-1026, "Hostname: %s", config->hostname);
+  cli_msg(0, "");
+}
+
 void
 cmd_eval(const struct f_line *expr)
 {
diff --git a/nest/cmds.h b/nest/cmds.h
index 194a9d7f..14c7293d 100644
--- a/nest/cmds.h
+++ b/nest/cmds.h
@@ -16,6 +16,7 @@ struct f_inst;
 void cmd_show_status(void);
 void cmd_show_symbols(struct sym_show_data *sym);
 void cmd_show_memory(void);
+void cmd_show_hostname(void);
 
 struct f_line;
 void cmd_eval(const struct f_line *expr);
diff --git a/nest/config.Y b/nest/config.Y
index 39bf6149..72ea0726 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -564,6 +564,9 @@ CF_CLI(SHOW STATUS,,, [[Show router status]])
 CF_CLI(SHOW MEMORY,,, [[Show memory usage]])
 { cmd_show_memory(); } ;
 
+CF_CLI(SHOW HOSTNAME,,, [[Show current hostname]])
+{ cmd_show_hostname(); } ;
+
 CF_CLI(SHOW PROTOCOLS, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocols]])
 { proto_apply_cmd($3, proto_cmd_show, 0, 0); } ;
 
-- 
2.20.1



More information about the Bird-users mailing list