forked from Mirror/frr
lib: add cli preprocessor for |
actions
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>
This commit is contained in:
parent
01e24c4a69
commit
fe6b47b9e9
|
@ -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. */
|
||||
|
|
|
@ -47,10 +47,10 @@
|
|||
#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 *);
|
||||
|
||||
|
|
62
lib/vty.c
62
lib/vty.c
|
@ -21,10 +21,13 @@
|
|||
|
||||
#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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue