From: Rodny Molina Date: Fri, 11 May 2018 05:15:48 +0000 (-0700) Subject: vtysh: Extending vtysh to allow question-mark cmds X-Git-Tag: frr-6.1-dev~430^2 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=a4364a44ae3180536b8f6faac0ca2f1404915385;p=mirror%2Ffrr.git vtysh: Extending vtysh to allow question-mark cmds 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 ?" 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 --- diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 01ba007767..785a16fba3 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -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 diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index f3e58f309e..ccfdd6557b 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -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); diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index cd59d8094b..3dd70983bc 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -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))