vlib: extend telnet protocol guard
[vpp.git] / src / vlib / unix / cli.c
index b553e12..e98eb34 100644 (file)
@@ -61,6 +61,7 @@
 #include <limits.h>
 #include <netinet/tcp.h>
 #include <math.h>
+#include <vppinfra/macros.h>
 
 /** ANSI escape code. */
 #define ESC "\x1b"
@@ -91,7 +92,7 @@
 
 /** Maximum depth into a byte stream from which to compile a Telnet
  * protocol message. This is a safety measure. */
-#define UNIX_CLI_MAX_DEPTH_TELNET 24
+#define UNIX_CLI_MAX_DEPTH_TELNET 32
 
 /** Maximum terminal width we will accept */
 #define UNIX_CLI_MAX_TERMINAL_WIDTH 512
@@ -241,6 +242,8 @@ typedef struct
    */
   u8 cursor_direction;
 
+  /** Macro tables for this session */
+  clib_macro_main_t macro_main;
 } unix_cli_file_t;
 
 /** Resets the pager buffer and other data.
@@ -491,11 +494,33 @@ typedef struct
 
   /** List of new sessions */
   unix_cli_new_session_t *new_sessions;
+
+  /** system default macro table */
+  clib_macro_main_t macro_main;
+
 } unix_cli_main_t;
 
 /** CLI global state */
 static unix_cli_main_t unix_cli_main;
 
+/** Return the macro main / tables we should use for this session
+ */
+static clib_macro_main_t *
+get_macro_main (void)
+{
+  unix_cli_main_t *cm = &unix_cli_main;
+  vlib_main_t *vm = vlib_get_main ();
+  vlib_process_t *cp = vlib_get_current_process (vm);
+  unix_cli_file_t *cf;
+
+  if (pool_is_free_index (cm->cli_file_pool, cp->output_function_arg))
+    return (&cm->macro_main);
+
+  cf = pool_elt_at_index (cm->cli_file_pool, cp->output_function_arg);
+
+  return (&cf->macro_main);
+}
+
 /**
  * @brief Search for a byte sequence in the action list.
  *
@@ -2563,6 +2588,25 @@ more:
       int rv __attribute__ ((unused)) = write (um->log_fd, lv, vec_len (lv));
     }
 
+  /* Run the command through the macro processor */
+  if (vec_len (cf->current_command))
+    {
+      u8 *expanded;
+      vec_validate (cf->current_command, vec_len (cf->current_command));
+      cf->current_command[vec_len (cf->current_command) - 1] = 0;
+      /* The macro expander expects proper C-strings, not vectors */
+      expanded = (u8 *) clib_macro_eval (&cf->macro_main,
+                                        (i8 *) cf->current_command,
+                                        1 /* complain */ ,
+                                        0 /* level */ ,
+                                        8 /* max_level */ );
+      /* Macro processor NULL terminates the return */
+      _vec_len (expanded) -= 1;
+      vec_reset_length (cf->current_command);
+      vec_append (cf->current_command, expanded);
+      vec_free (expanded);
+    }
+
   /* Build an unformat structure around our command */
   unformat_init_vector (&input, cf->current_command);
 
@@ -2667,6 +2711,7 @@ unix_cli_kill (unix_cli_main_t * cm, uword cli_file_index)
   clib_file_del (fm, uf);
 
   unix_cli_file_free (cf);
+  clib_macro_free (&cf->macro_main);
   pool_put (cm->cli_file_pool, cf);
 }
 
@@ -2884,6 +2929,7 @@ unix_cli_file_add (unix_cli_main_t * cm, char *name, int fd)
 
   pool_get (cm->cli_file_pool, cf);
   clib_memset (cf, 0, sizeof (*cf));
+  clib_macro_init (&cf->macro_main);
 
   template.read_function = unix_cli_read_ready;
   template.write_function = unix_cli_write_ready;
@@ -2896,6 +2942,8 @@ unix_cli_file_add (unix_cli_main_t * cm, char *name, int fd)
   cf->clib_file_index = clib_file_add (fm, &template);
   cf->output_vector = 0;
   cf->input_vector = 0;
+  vec_validate (cf->current_command, 0);
+  _vec_len (cf->current_command) = 0;
 
   vlib_start_process (vm, n->runtime_index);
 
@@ -3905,6 +3953,121 @@ VLIB_CLI_COMMAND (cli_unix_wait_cmd, static) = {
 };
 /* *INDENT-ON* */
 
+static clib_error_t *
+echo_cmd (vlib_main_t * vm,
+         unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    {
+      vlib_cli_output (vm, "");
+      return 0;
+    }
+
+  vlib_cli_output (vm, "%v", line_input->buffer);
+
+  unformat_free (line_input);
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (cli_unix_echo_cmd, static) = {
+  .path = "echo",
+  .short_help = "echo <rest-of-line>",
+  .function = echo_cmd,
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+define_cmd_fn (vlib_main_t * vm,
+              unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+  u8 *macro_name;
+  unformat_input_t _line_input, *line_input = &_line_input;
+  clib_macro_main_t *mm = get_macro_main ();
+  clib_error_t *error;
+
+  if (!unformat (input, "%s", &macro_name))
+    return clib_error_return (0, "missing variable name...");
+
+  /* Remove white space */
+  (void) unformat (input, "");
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    {
+      error = clib_error_return (0, "missing value for '%s'...", macro_name);
+      vec_free (macro_name);
+      return error;
+    }
+  /* the macro expander expects c-strings, not vectors... */
+  vec_add1 (line_input->buffer, 0);
+  clib_macro_set_value (mm, (char *) macro_name, (char *) line_input->buffer);
+  vec_free (macro_name);
+  unformat_free (line_input);
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (define_cmd, static) = {
+  .path = "define",
+  .short_help = "define <variable-name> <value>",
+  .function = define_cmd_fn,
+};
+
+/* *INDENT-ON* */
+
+static clib_error_t *
+undefine_cmd_fn (vlib_main_t * vm,
+                unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+  u8 *macro_name;
+  clib_macro_main_t *mm = get_macro_main ();
+
+  if (!unformat (input, "%s", &macro_name))
+    return clib_error_return (0, "missing variable name...");
+
+  if (clib_macro_unset (mm, (char *) macro_name))
+    vlib_cli_output (vm, "%s wasn't set...", macro_name);
+
+  vec_free (macro_name);
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (undefine_cmd, static) = {
+  .path = "undefine",
+  .short_help = "undefine <variable-name>",
+  .function = undefine_cmd_fn,
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+show_macro_cmd_fn (vlib_main_t * vm,
+                  unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+  clib_macro_main_t *mm = get_macro_main ();
+  int evaluate = 1;
+
+  if (unformat (input, "noevaluate %=", &evaluate, 0))
+    ;
+  else if (unformat (input, "noeval %=", &evaluate, 0))
+    ;
+
+  vlib_cli_output (vm, "%U", format_clib_macro_main, mm, evaluate);
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_macro, static) = {
+  .path = "show macro",
+  .short_help = "show macro [noevaluate]",
+  .function = show_macro_cmd_fn,
+};
+/* *INDENT-ON* */
+
 static clib_error_t *
 unix_cli_init (vlib_main_t * vm)
 {
@@ -3913,6 +4076,7 @@ unix_cli_init (vlib_main_t * vm)
   /* Breadcrumb to indicate the new session process
    * has not been started */
   cm->new_session_process_node_index = ~0;
+  clib_macro_init (&cm->macro_main);
 
   return 0;
 }