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),
|
DEFINE_KOOH(cmd_execute_done, (struct vty * vty, const char *cmd_exec),
|
||||||
(vty, 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,
|
int cmd_execute(struct vty *vty, const char *cmd,
|
||||||
const struct cmd_element **matched, int vtysh)
|
const struct cmd_element **matched, int vtysh)
|
||||||
{
|
{
|
||||||
|
@ -2720,6 +2769,10 @@ void cmd_init(int terminal)
|
||||||
uname(&names);
|
uname(&names);
|
||||||
qobj_init();
|
qobj_init();
|
||||||
|
|
||||||
|
/* register command preprocessors */
|
||||||
|
hook_register(cmd_execute, handle_pipe_action);
|
||||||
|
hook_register(cmd_execute_done, handle_pipe_action_done);
|
||||||
|
|
||||||
varhandlers = list_new();
|
varhandlers = list_new();
|
||||||
|
|
||||||
/* Allocate initial top vector of commands. */
|
/* Allocate initial top vector of commands. */
|
||||||
|
|
|
@ -47,10 +47,10 @@
|
||||||
#define FRR_CONFIG_ARGS "@CONFIG_ARGS@"
|
#define FRR_CONFIG_ARGS "@CONFIG_ARGS@"
|
||||||
|
|
||||||
#define FRR_DEFAULT_MOTD \
|
#define FRR_DEFAULT_MOTD \
|
||||||
"\r\n" \
|
"\n" \
|
||||||
"Hello, this is " FRR_FULL_NAME " (version " FRR_VERSION ").\r\n" \
|
"Hello, this is " FRR_FULL_NAME " (version " FRR_VERSION ").\n" \
|
||||||
FRR_COPYRIGHT "\r\n" \
|
FRR_COPYRIGHT "\n" \
|
||||||
GIT_INFO "\r\n"
|
GIT_INFO "\n"
|
||||||
|
|
||||||
pid_t pid_output (const char *);
|
pid_t pid_output (const char *);
|
||||||
|
|
||||||
|
|
62
lib/vty.c
62
lib/vty.c
|
@ -21,10 +21,13 @@
|
||||||
|
|
||||||
#include <zebra.h>
|
#include <zebra.h>
|
||||||
|
|
||||||
|
#include <lib/version.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
#include "linklist.h"
|
#include "linklist.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
#include <lib/version.h>
|
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "sockunion.h"
|
#include "sockunion.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
@ -35,6 +38,7 @@
|
||||||
#include "privs.h"
|
#include "privs.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "libfrr.h"
|
#include "libfrr.h"
|
||||||
|
#include "frrstr.h"
|
||||||
|
|
||||||
#include <arpa/telnet.h>
|
#include <arpa/telnet.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
@ -109,6 +113,31 @@ void vty_endframe(struct vty *vty, const char *endtext)
|
||||||
vty->frame_pos = 0;
|
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. */
|
/* VTY standard output function. */
|
||||||
int vty_out(struct vty *vty, const char *format, ...)
|
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;
|
int size = 1024;
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
char *p = NULL;
|
char *p = NULL;
|
||||||
|
char *filtered;
|
||||||
|
|
||||||
if (vty->frame_pos) {
|
if (vty->frame_pos) {
|
||||||
vty->frame_pos = 0;
|
vty->frame_pos = 0;
|
||||||
|
@ -158,11 +188,28 @@ int vty_out(struct vty *vty, const char *format, ...)
|
||||||
if (!p)
|
if (!p)
|
||||||
p = buf;
|
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. */
|
/* Pointer p must point out buffer. */
|
||||||
if (vty->type != VTY_TERM)
|
if (vty->type != VTY_TERM)
|
||||||
buffer_put(vty->obuf, (uint8_t *)p, len);
|
buffer_put(vty->obuf, (uint8_t *)filtered,
|
||||||
|
strlen(filtered));
|
||||||
else
|
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 is not different with buf, it is allocated buffer. */
|
||||||
if (p != buf)
|
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)
|
static int vty_command(struct vty *vty, char *buf)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
vector vline;
|
|
||||||
const char *protocolname;
|
const char *protocolname;
|
||||||
char *cp = NULL;
|
char *cp = NULL;
|
||||||
|
|
||||||
|
@ -427,11 +473,6 @@ static int vty_command(struct vty *vty, char *buf)
|
||||||
/* now log the command */
|
/* now log the command */
|
||||||
zlog_err("%s%s", prompt_str, buf);
|
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
|
#ifdef CONSUMED_TIME_CHECK
|
||||||
{
|
{
|
||||||
|
@ -442,7 +483,7 @@ static int vty_command(struct vty *vty, char *buf)
|
||||||
GETRUSAGE(&before);
|
GETRUSAGE(&before);
|
||||||
#endif /* CONSUMED_TIME_CHECK */
|
#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 */
|
/* Get the name of the protocol if any */
|
||||||
protocolname = frr_protoname;
|
protocolname = frr_protoname;
|
||||||
|
@ -475,7 +516,6 @@ static int vty_command(struct vty *vty, char *buf)
|
||||||
vty_out(vty, "%% Command incomplete.\n");
|
vty_out(vty, "%% Command incomplete.\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cmd_free_strvec(vline);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
#ifndef _ZEBRA_VTY_H
|
#ifndef _ZEBRA_VTY_H
|
||||||
#define _ZEBRA_VTY_H
|
#define _ZEBRA_VTY_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "sockunion.h"
|
#include "sockunion.h"
|
||||||
|
@ -47,6 +50,10 @@ struct vty {
|
||||||
/* Failure count */
|
/* Failure count */
|
||||||
int fail;
|
int fail;
|
||||||
|
|
||||||
|
/* Output filer regex */
|
||||||
|
bool filter;
|
||||||
|
regex_t include;
|
||||||
|
|
||||||
/* Output buffer. */
|
/* Output buffer. */
|
||||||
struct buffer *obuf;
|
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 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_frame(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
|
||||||
extern void vty_endframe(struct vty *, const char *);
|
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_read_config(const char *, char *);
|
||||||
extern void vty_time_print(struct vty *, int);
|
extern void vty_time_print(struct vty *, int);
|
||||||
|
|
Loading…
Reference in a new issue