]> git.puffer.fish Git - mirror/frr.git/commitdiff
vtysh: Extending vtysh to allow question-mark cmds 2221/head
authorRodny Molina <rmolina@linkedin.com>
Fri, 11 May 2018 05:15:48 +0000 (22:15 -0700)
committerRodny Molina <rmolina@linkedin.com>
Sun, 13 May 2018 01:59:11 +0000 (18:59 -0700)
Currently, "vtysh -c" interface does not provide a logic to parse
commands ending with '?' character. In consequence, the following behavior
is observed:

$ vtysh -c "show bgp ?"
 % Unknown command.

With these changes, i'm extending FRR's parser to be able to handle
these commands, which allow a more friendly interaction with users
that rely on "vtysh -c" interface. The typical use-case here is for
scenarios in which the final users relie on external/their-own CLI and
require a friendly interface to FRR's vtysh cli.

$ vtysh -c "show bgp ?"
  <cr>
   A.B.C.D               Network in the BGP routing table to
   display
   A.B.C.D/M             IPv4 prefix
   X:X::X:X              Network in the BGP routing table to display
   X:X::X:X/M            IPv6 prefix
   attribute-info        List all bgp attribute information
   cidr-only             Display only routes with non-natural netmasks
   community             Display routes matching the communities
   community-info        List all bgp community information
 ...

Signed-off-by: Rodny Molina <rmolina@linkedin.com>
vtysh/vtysh.c
vtysh/vtysh.h
vtysh/vtysh_main.c

index 01ba00776781efeb93c14a57ffd3c2018a7f521c..785a16fba315ae9bb22e671cb234aaadf9df6d7e 100644 (file)
@@ -845,27 +845,29 @@ int vtysh_config_from_file(struct vty *vty, FILE *fp)
        return (retcode);
 }
 
-/* We don't care about the point of the cursor when '?' is typed. */
-static int vtysh_rl_describe(void)
+/*
+ * Function processes cli commands terminated with '?' character when entered
+ * through either 'vtysh' or 'vtysh -c' interfaces.
+ */
+static int vtysh_process_questionmark(const char *input, int input_len)
 {
-       int ret;
+       int ret, width = 0;
        unsigned int i;
-       vector vline;
-       vector describe;
-       int width;
+       vector vline, describe;
        struct cmd_token *token;
 
-       vline = cmd_make_strvec(rl_line_buffer);
+       if (!input)
+               return 1;
+
+       vline = cmd_make_strvec(input);
 
        /* In case of '> ?'. */
        if (vline == NULL) {
                vline = vector_init(1);
                vector_set(vline, NULL);
-       } else if (rl_end && isspace((int)rl_line_buffer[rl_end - 1]))
+       } else if (input_len && isspace((int)input[input_len - 1]))
                vector_set(vline, NULL);
 
-       fprintf(stdout, "\n");
-
        describe = cmd_describe_command(vline, vty, &ret);
 
        /* Ambiguous and no match error. */
@@ -874,7 +876,6 @@ static int vtysh_rl_describe(void)
                cmd_free_strvec(vline);
                vector_free(describe);
                fprintf(stdout, "%% Ambiguous command.\n");
-               rl_on_new_line();
                return 0;
                break;
        case CMD_ERR_NO_MATCH:
@@ -882,7 +883,6 @@ static int vtysh_rl_describe(void)
                if (describe)
                        vector_free(describe);
                fprintf(stdout, "%% There is no matched command.\n");
-               rl_on_new_line();
                return 0;
                break;
        }
@@ -932,9 +932,61 @@ static int vtysh_rl_describe(void)
        cmd_free_strvec(vline);
        vector_free(describe);
 
+       return 0;
+}
+
+/*
+ * Entry point for user commands terminated with '?' character and typed through
+ * the usual vtysh's stdin interface. This is the function being registered with
+ * readline() api's.
+ */
+static int vtysh_rl_describe(void)
+{
+       int ret;
+
+       fprintf(stdout, "\n");
+
+       ret = vtysh_process_questionmark(rl_line_buffer, rl_end);
        rl_on_new_line();
 
-       return 0;
+       return ret;
+}
+
+/*
+ * Function in charged of processing vtysh instructions terminating with '?'
+ * character and received through the 'vtysh -c' interface. If user's
+ * instruction is well-formatted, we will call the same processing routine
+ * utilized by the traditional vtysh's stdin interface.
+ */
+int vtysh_execute_command_questionmark(char *input)
+{
+       int input_len, qmark_count = 0;
+       const char *str;
+
+       if (!(input && *input))
+               return 1;
+
+       /* Finding out question_mark count and strlen */
+       for (str = input; *str; ++str) {
+               if (*str == '?')
+                       qmark_count++;
+       }
+       input_len = str - input;
+
+       /*
+        * Verify that user's input terminates in '?' and that patterns such as
+        * 'cmd ? subcmd ?' are prevented.
+        */
+       if (qmark_count != 1 || input[input_len - 1] != '?')
+               return 1;
+
+       /*
+        * Questionmark-processing function is not expecting to receive '?'
+        * character in input string.
+        */
+       input[input_len - 1] = '\0';
+
+       return vtysh_process_questionmark(input, input_len - 1);
 }
 
 /* Result of cmd_complete_command() call will be stored here
index f3e58f309e8d85516864d05dc30b6678c1141dbf..ccfdd6557b425da2fda33c42419c026330030e05 100644 (file)
@@ -71,6 +71,7 @@ void vtysh_user_init(void);
 
 int vtysh_execute(const char *);
 int vtysh_execute_no_pager(const char *);
+int vtysh_execute_command_questionmark(char *input);
 
 char *vtysh_prompt(void);
 
index cd59d8094b95c35541f17cea470ba93a2c68397f..3dd70983bc27a8847a11670ce840f6d4594b3453 100644 (file)
@@ -611,7 +611,16 @@ int main(int argc, char **argv, char **env)
                        if (logfile)
                                log_it(cmd->line);
 
-                       ret = vtysh_execute_no_pager(cmd->line);
+                       /*
+                        * Parsing logic for regular commands will be different than
+                        * for those commands requiring further processing, such as
+                        * cli instructions terminating with question-mark character.
+                        */
+                       if (!vtysh_execute_command_questionmark(cmd->line))
+                               ret = CMD_SUCCESS;
+                       else
+                               ret = vtysh_execute_no_pager(cmd->line);
+
                        if (!no_error
                            && !(ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON
                                 || ret == CMD_WARNING))