]> git.proxmox.com Git - mirror_frr.git/commitdiff
lib: add cli preprocessor for `|` actions
authorQuentin Young <qlyoung@cumulusnetworks.com>
Sun, 13 May 2018 00:14:22 +0000 (20:14 -0400)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Wed, 6 Jun 2018 16:15:34 +0000 (16:15 +0000)
This patch adds a CLI preprocessor function that activates when `|` is
found in the command. This is the start of adding support for some text
processing utilities intended for inline use. The first one implemented
here is `| include`, which provides grep-like filtering of command
output.

Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
lib/command.c
lib/version.h.in
lib/vty.c
lib/vty.h

index 97e60a5929148d8b0a078b19adc0cd6e8f716228..5b2783d326524182a790105df97a2cf4b8d3f313 100644 (file)
@@ -1174,6 +1174,55 @@ DECLARE_KOOH(cmd_execute_done, (struct vty * vty, const char *cmd_exec),
 DEFINE_KOOH(cmd_execute_done, (struct vty * vty, const char *cmd_exec),
            (vty, cmd_exec));
 
+/*
+ * cmd_execute hook subscriber to handle `|` actions.
+ */
+static int handle_pipe_action(struct vty *vty, const char *cmd_in,
+                             char **cmd_out)
+{
+       /* look for `|` */
+       char *orig, *working, *token;
+       char *pipe = strstr(cmd_in, "| ");
+
+       if (!pipe)
+               return 0;
+
+       /* duplicate string for processing purposes, not including pipe */
+       orig = working = XSTRDUP(MTYPE_TMP, pipe + 2);
+
+       /* retrieve action */
+       token = strsep(&working, " ");
+
+       /* match result to known actions */
+       if (strmatch(token, "include")) {
+               /* the remaining text should be a regexp */
+               char *regexp = working;
+               bool succ = vty_set_include(vty, regexp);
+               if (!succ) {
+                       vty_out(vty, "%% Bad regexp '%s'", regexp);
+                       goto fail;
+               }
+               cmd_out = XSTRDUP(MTYPE_TMP, cmd_in);
+               *(strstr(cmd_in, "|")) = '\0';
+       } else {
+               vty_out(vty, "%% Unknown action '%s'", token);
+               goto fail;
+       }
+
+fail:
+       XFREE(MTYPE_TMP, orig);
+       return 0;
+}
+
+static int handle_pipe_action_done(struct vty *vty, const char *cmd_exec)
+{
+       if (vty->filter) {
+               vty_set_include(vty, NULL);
+               vty_out(vty, "\n");
+       }
+       return 0;
+}
+
 int cmd_execute(struct vty *vty, const char *cmd,
                const struct cmd_element **matched, int vtysh)
 {
@@ -2720,6 +2769,10 @@ void cmd_init(int terminal)
        uname(&names);
        qobj_init();
 
+       /* register command preprocessors */
+       hook_register(cmd_execute, handle_pipe_action);
+       hook_register(cmd_execute_done, handle_pipe_action_done);
+
        varhandlers = list_new();
 
        /* Allocate initial top vector of commands. */
index d9eabb9f8170595f305b3b1d32da97507f43b4a5..52c10f7d6898d25b1d176ff2c803bb85df227253 100644 (file)
 #define FRR_CONFIG_ARGS "@CONFIG_ARGS@"
 
 #define FRR_DEFAULT_MOTD \
-       "\r\n" \
-       "Hello, this is " FRR_FULL_NAME " (version " FRR_VERSION ").\r\n" \
-       FRR_COPYRIGHT "\r\n" \
-       GIT_INFO "\r\n"
+       "\n" \
+       "Hello, this is " FRR_FULL_NAME " (version " FRR_VERSION ").\n" \
+       FRR_COPYRIGHT "\n" \
+       GIT_INFO "\n"
 
 pid_t pid_output (const char *);
 
index e8463da3d7350c12331bcec3d4279414edd574bc..5a30bfa8adf3d3394fc65b34f146de5132cf1766 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
 
 #include <zebra.h>
 
+#include <lib/version.h>
+#include <sys/types.h>
+#include <regex.h>
+
 #include "linklist.h"
 #include "thread.h"
 #include "buffer.h"
-#include <lib/version.h>
 #include "command.h"
 #include "sockunion.h"
 #include "memory.h"
@@ -35,6 +38,7 @@
 #include "privs.h"
 #include "network.h"
 #include "libfrr.h"
+#include "frrstr.h"
 
 #include <arpa/telnet.h>
 #include <termios.h>
@@ -109,6 +113,31 @@ void vty_endframe(struct vty *vty, const char *endtext)
        vty->frame_pos = 0;
 }
 
+bool vty_set_include(struct vty *vty, const char *regexp)
+{
+       int errcode;
+       bool ret = true;
+       char errbuf[256];
+
+       if (!regexp) {
+               memset(&vty->include, 0x00, sizeof(vty->include));
+               vty->filter = false;
+               return true;
+       }
+
+       errcode = regcomp(&vty->include, regexp,
+                         REG_EXTENDED | REG_NEWLINE | REG_NOSUB);
+       if (errcode) {
+               ret = false;
+               regerror(ret, &vty->include, errbuf, sizeof(errbuf));
+               vty_out(vty, "%% Regex compilation error: %s", errbuf);
+       } else {
+               vty->filter = true;
+       }
+
+       return ret;
+}
+
 /* VTY standard output function. */
 int vty_out(struct vty *vty, const char *format, ...)
 {
@@ -117,6 +146,7 @@ int vty_out(struct vty *vty, const char *format, ...)
        int size = 1024;
        char buf[1024];
        char *p = NULL;
+       char *filtered;
 
        if (vty->frame_pos) {
                vty->frame_pos = 0;
@@ -158,11 +188,28 @@ int vty_out(struct vty *vty, const char *format, ...)
                if (!p)
                        p = buf;
 
+               /* filter buffer */
+               if (vty->filter) {
+                       vector lines = frrstr_split_vec(buf, "\n");
+                       frrstr_filter_vec(lines, &vty->include);
+                       if (buf[strlen(buf) - 1] == '\n' && vector_active(lines) > 0)
+                               vector_set(lines, XSTRDUP(MTYPE_TMP, ""));
+                       filtered = frrstr_join_vec(lines, "\n");
+                       frrstr_strvec_free(lines);
+               } else {
+                       filtered = p;
+               }
+
                /* Pointer p must point out buffer. */
                if (vty->type != VTY_TERM)
-                       buffer_put(vty->obuf, (uint8_t *)p, len);
+                       buffer_put(vty->obuf, (uint8_t *)filtered,
+                                  strlen(filtered));
                else
-                       buffer_put_crlf(vty->obuf, (uint8_t *)p, len);
+                       buffer_put_crlf(vty->obuf, (uint8_t *)filtered,
+                                       strlen(filtered));
+
+               if (vty->filter)
+                       XFREE(MTYPE_TMP, filtered);
 
                /* If p is not different with buf, it is allocated buffer.  */
                if (p != buf)
@@ -391,7 +438,6 @@ static void vty_auth(struct vty *vty, char *buf)
 static int vty_command(struct vty *vty, char *buf)
 {
        int ret;
-       vector vline;
        const char *protocolname;
        char *cp = NULL;
 
@@ -427,11 +473,6 @@ static int vty_command(struct vty *vty, char *buf)
                /* now log the command */
                zlog_err("%s%s", prompt_str, buf);
        }
-       /* Split readline string up into the vector */
-       vline = cmd_make_strvec(buf);
-
-       if (vline == NULL)
-               return CMD_SUCCESS;
 
 #ifdef CONSUMED_TIME_CHECK
        {
@@ -442,7 +483,7 @@ static int vty_command(struct vty *vty, char *buf)
                GETRUSAGE(&before);
 #endif /* CONSUMED_TIME_CHECK */
 
-               ret = cmd_execute_command(vline, vty, NULL, 0);
+               ret = cmd_execute(vty, buf, NULL, 0);
 
                /* Get the name of the protocol if any */
                protocolname = frr_protoname;
@@ -475,7 +516,6 @@ static int vty_command(struct vty *vty, char *buf)
                        vty_out(vty, "%% Command incomplete.\n");
                        break;
                }
-       cmd_free_strvec(vline);
 
        return ret;
 }
index 6e5ff13ffdc25b98e52786e6c2266f7674098c14..32fd471f18211b94ac131c6e1d942986268406f5 100644 (file)
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -21,6 +21,9 @@
 #ifndef _ZEBRA_VTY_H
 #define _ZEBRA_VTY_H
 
+#include <sys/types.h>
+#include <regex.h>
+
 #include "thread.h"
 #include "log.h"
 #include "sockunion.h"
@@ -47,6 +50,10 @@ struct vty {
        /* Failure count */
        int fail;
 
+       /* Output filer regex */
+       bool filter;
+       regex_t include;
+
        /* Output buffer. */
        struct buffer *obuf;
 
@@ -223,6 +230,7 @@ extern struct vty *vty_stdio(void (*atclose)(int isexit));
 extern int vty_out(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
 extern void vty_frame(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
 extern void vty_endframe(struct vty *, const char *);
+bool vty_set_include(struct vty *vty, const char *regexp);
 
 extern void vty_read_config(const char *, char *);
 extern void vty_time_print(struct vty *, int);