summaryrefslogtreecommitdiffstats
path: root/vtysh/vtysh.c
diff options
context:
space:
mode:
Diffstat (limited to 'vtysh/vtysh.c')
-rw-r--r--vtysh/vtysh.c165
1 files changed, 113 insertions, 52 deletions
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 76343ded6..097f39fcf 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -46,6 +46,9 @@
DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy")
+/* Destination for vtysh output */
+FILE *outputfile;
+
/* Struct VTY. */
struct vty *vty;
@@ -138,16 +141,25 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
bufvalid += nread;
- end = memmem(buf, bufvalid - buf, terminator,
- sizeof(terminator));
- if (end + sizeof(terminator) + 1 > bufvalid)
+ if (bufvalid - buf >= 4)
+ end = memmem(bufvalid - 4, 4, terminator,
+ sizeof(terminator));
+
+ if (end && end + sizeof(terminator) + 1 > bufvalid)
/* found \0\0\0 but return code hasn't been read yet */
end = NULL;
if (end)
ret = end[sizeof(terminator)];
- while (bufvalid > buf && (end > buf || !end)) {
- size_t textlen = (end ? end : bufvalid) - buf;
+ /*
+ * calculate # bytes we have, up to & not including the
+ * terminator if present
+ */
+ size_t textlen = (end ? end : bufvalid) - buf;
+
+ /* feed line processing callback if present */
+ while (callback && bufvalid > buf && (end > buf || !end)) {
+ textlen = (end ? end : bufvalid) - buf;
char *eol = memchr(buf, '\n', textlen);
if (eol)
/* line break */
@@ -165,8 +177,7 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
/* continue reading */
break;
- /* eol is at a line end now, either \n => \0 or \0\0\0
- */
+ /* eol is at line end now, either \n => \0 or \0\0\0 */
assert(eol && eol <= bufvalid);
if (fp) {
@@ -186,6 +197,14 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
end -= eol - buf;
}
+ /* else if no callback, dump raw */
+ if (!callback) {
+ if (fp)
+ fwrite(buf, 1, textlen, fp);
+ memmove(buf, buf + textlen, bufvalid - buf - textlen);
+ bufvalid -= textlen;
+ }
+
if (bufvalid == buf + bufsz) {
char *new;
bufsz *= 2;
@@ -375,21 +394,21 @@ static int vtysh_execute_func(const char *line, int pager)
fprintf(stdout, "%% Command incomplete.\n");
break;
case CMD_SUCCESS_DAEMON: {
- /* FIXME: Don't open pager for exit commands. popen() causes
- * problems
- * if exited from vtysh at all. This hack shouldn't cause any
- * problem
- * but is really ugly. */
- if (pager && vtysh_pager_name
+ /*
+ * FIXME: Don't open pager for exit commands. popen() causes
+ * problems if exited from vtysh at all. This hack shouldn't
+ * cause any problem but is really ugly.
+ */
+ fp = outputfile;
+ if (pager && vtysh_pager_name && outputfile == stdout
&& (strncmp(line, "exit", 4) != 0)) {
fp = popen(vtysh_pager_name, "w");
if (fp == NULL) {
perror("popen failed for pager");
- fp = stdout;
+ fp = outputfile;
} else
closepager = 1;
- } else
- fp = stdout;
+ }
if (!strcmp(cmd->string, "configure terminal")) {
for (i = 0; i < array_size(vtysh_client); i++) {
@@ -405,7 +424,7 @@ static int vtysh_execute_func(const char *line, int pager)
if (vline == NULL) {
if (pager && vtysh_pager_name && fp
- && closepager) {
+ && fp != outputfile && closepager) {
if (pclose(fp) == -1) {
perror("pclose failed for pager");
}
@@ -455,7 +474,7 @@ static int vtysh_execute_func(const char *line, int pager)
(*cmd->func)(cmd, vty, 0, NULL);
}
}
- if (pager && vtysh_pager_name && fp && closepager) {
+ if (pager && vtysh_pager_name && fp && closepager && fp != outputfile) {
if (pclose(fp) == -1) {
perror("pclose failed for pager");
}
@@ -537,19 +556,19 @@ int vtysh_mark_file(const char *filename)
switch (vty->node) {
case LDP_IPV4_IFACE_NODE:
if (strncmp(vty_buf_copy, " ", 3)) {
- fprintf(stdout, " end\n");
+ fprintf(outputfile, " end\n");
vty->node = LDP_IPV4_NODE;
}
break;
case LDP_IPV6_IFACE_NODE:
if (strncmp(vty_buf_copy, " ", 3)) {
- fprintf(stdout, " end\n");
+ fprintf(outputfile, " end\n");
vty->node = LDP_IPV6_NODE;
}
break;
case LDP_PSEUDOWIRE_NODE:
if (strncmp(vty_buf_copy, " ", 2)) {
- fprintf(stdout, " end\n");
+ fprintf(outputfile, " end\n");
vty->node = LDP_L2VPN_NODE;
}
break;
@@ -558,7 +577,7 @@ int vtysh_mark_file(const char *filename)
}
if (vty_buf_trimmed[0] == '!' || vty_buf_trimmed[0] == '#') {
- fprintf(stdout, "%s", vty->buf);
+ fprintf(outputfile, "%s", vty->buf);
continue;
}
@@ -566,7 +585,7 @@ int vtysh_mark_file(const char *filename)
vline = cmd_make_strvec(vty->buf);
if (vline == NULL) {
- fprintf(stdout, "%s", vty->buf);
+ fprintf(outputfile, "%s", vty->buf);
continue;
}
@@ -609,15 +628,15 @@ int vtysh_mark_file(const char *filename)
|| prev_node == BGP_IPV6M_NODE
|| prev_node == BGP_EVPN_NODE)
&& (tried == 1)) {
- fprintf(stdout, "exit-address-family\n");
+ fprintf(outputfile, "exit-address-family\n");
} else if ((prev_node == BGP_EVPN_VNI_NODE)
&& (tried == 1)) {
- fprintf(stdout, "exit-vni\n");
+ fprintf(outputfile, "exit-vni\n");
} else if ((prev_node == KEYCHAIN_KEY_NODE)
&& (tried == 1)) {
- fprintf(stdout, "exit\n");
+ fprintf(outputfile, "exit\n");
} else if (tried) {
- fprintf(stdout, "end\n");
+ fprintf(outputfile, "end\n");
}
}
/* If command didn't succeed in any node, continue with return
@@ -667,12 +686,12 @@ int vtysh_mark_file(const char *filename)
u_int i;
int cmd_stat = CMD_SUCCESS;
- fprintf(stdout, "%s", vty->buf);
+ fprintf(outputfile, "%s", vty->buf);
for (i = 0; i < array_size(vtysh_client); i++) {
if (cmd->daemon & vtysh_client[i].flag) {
cmd_stat = vtysh_client_execute(
&vtysh_client[i], vty->buf,
- stdout);
+ outputfile);
if (cmd_stat != CMD_SUCCESS)
break;
}
@@ -686,7 +705,7 @@ int vtysh_mark_file(const char *filename)
}
}
/* This is the end */
- fprintf(stdout, "\nend\n");
+ fprintf(outputfile, "\nend\n");
vty_close(vty);
XFREE(MTYPE_VTYSH_CMD, vty_buf_copy);
@@ -749,7 +768,7 @@ int vtysh_config_from_file(struct vty *vty, FILE *fp)
if (cmd->daemon & vtysh_client[i].flag) {
cmd_stat = vtysh_client_execute(
&vtysh_client[i], vty->buf,
- stdout);
+ outputfile);
/*
* CMD_WARNING - Can mean that the
* command was
@@ -1854,7 +1873,7 @@ DEFUN (vtysh_show_thread,
fprintf(stdout, "Thread statistics for %s:\n",
vtysh_client[i].name);
ret = vtysh_client_execute(&vtysh_client[i], line,
- stdout);
+ outputfile);
fprintf(stdout, "\n");
}
return ret;
@@ -1875,7 +1894,7 @@ DEFUN (vtysh_show_work_queues,
fprintf(stdout, "Work queue statistics for %s:\n",
vtysh_client[i].name);
ret = vtysh_client_execute(&vtysh_client[i], line,
- stdout);
+ outputfile);
fprintf(stdout, "\n");
}
@@ -1905,7 +1924,7 @@ DEFUN (vtysh_show_work_queues_daemon,
}
ret = vtysh_client_execute(&vtysh_client[i], "show work-queues\n",
- stdout);
+ outputfile);
return ret;
}
@@ -1932,9 +1951,9 @@ static int show_per_daemon(const char *line, const char *headline)
for (i = 0; i < array_size(vtysh_client); i++)
if (vtysh_client[i].fd >= 0) {
- fprintf(stdout, headline, vtysh_client[i].name);
+ fprintf(outputfile, headline, vtysh_client[i].name);
ret = vtysh_client_execute(&vtysh_client[i], line,
- stdout);
+ outputfile);
fprintf(stdout, "\n");
}
@@ -2226,20 +2245,19 @@ DEFUN (vtysh_write_terminal,
{
u_int i;
char line[] = "do write terminal\n";
- FILE *fp = NULL;
+ FILE *fp = outputfile;
- if (vtysh_pager_name) {
+ if (fp == stdout && vtysh_pager_name) {
fp = popen(vtysh_pager_name, "w");
if (fp == NULL) {
perror("popen");
exit(1);
}
- } else
- fp = stdout;
+ }
- vty_out(vty, "Building configuration...\n");
- vty_out(vty, "\nCurrent configuration:\n");
- vty_out(vty, "!\n");
+ fprintf(outputfile, "Building configuration...\n");
+ fprintf(outputfile, "\nCurrent configuration:\n");
+ fprintf(outputfile, "!\n");
for (i = 0; i < array_size(vtysh_client); i++)
if ((argc < 3)
@@ -2251,7 +2269,7 @@ DEFUN (vtysh_write_terminal,
vtysh_config_dump(fp);
- if (vtysh_pager_name && fp) {
+ if (vtysh_pager_name && fp && fp != outputfile) {
fflush(fp);
if (pclose(fp) == -1) {
perror("pclose");
@@ -2260,7 +2278,7 @@ DEFUN (vtysh_write_terminal,
fp = NULL;
}
- vty_out(vty, "end\n");
+ fprintf(outputfile, "end\n");
return CMD_SUCCESS;
}
@@ -2429,7 +2447,7 @@ DEFUN (vtysh_write_memory,
char line[] = "do write memory\n";
u_int i;
- fprintf(stdout,
+ fprintf(outputfile,
"Note: this version of vtysh never writes vtysh.conf\n");
/* If integrated frr.conf explicitely set. */
@@ -2441,7 +2459,7 @@ DEFUN (vtysh_write_memory,
if (i < array_size(vtysh_client) && vtysh_client[i].fd != -1)
ret = vtysh_client_execute(&vtysh_client[i],
"do write integrated",
- stdout);
+ outputfile);
if (ret != CMD_SUCCESS) {
printf("\nWarning: attempting direct configuration write without "
@@ -2452,10 +2470,10 @@ DEFUN (vtysh_write_memory,
return ret;
}
- fprintf(stdout, "Building Configuration...\n");
+ fprintf(outputfile, "Building Configuration...\n");
for (i = 0; i < array_size(vtysh_client); i++)
- ret = vtysh_client_execute(&vtysh_client[i], line, stdout);
+ ret = vtysh_client_execute(&vtysh_client[i], line, outputfile);
return ret;
}
@@ -2484,7 +2502,7 @@ DEFUN (vtysh_terminal_length,
lines = strtol(argv[idx_number]->arg, &endptr, 10);
if (lines < 0 || lines > 512 || *endptr != '\0') {
- vty_out(vty, "length is malformed\n");
+ fprintf(outputfile, "length is malformed\n");
return CMD_WARNING;
}
@@ -2527,8 +2545,8 @@ DEFUN (vtysh_show_daemons,
for (i = 0; i < array_size(vtysh_client); i++)
if (vtysh_client[i].fd >= 0)
- vty_out(vty, " %s", vtysh_client[i].name);
- vty_out(vty, "\n");
+ fprintf(outputfile, " %s", vtysh_client[i].name);
+ fprintf(outputfile, "\n");
return CMD_SUCCESS;
}
@@ -2703,6 +2721,38 @@ DEFUN (config_list,
return cmd_list_cmds(vty, argc == 2);
}
+DEFUN (vtysh_output_file,
+ vtysh_output_file_cmd,
+ "output file FILE",
+ "Direct vtysh output to file\n"
+ "Direct vtysh output to file\n"
+ "Path to dump output to\n")
+{
+ const char *path = argv[argc - 1]->arg;
+ outputfile = fopen(path, "a");
+ if (!outputfile) {
+ fprintf(stdout, "Failed to open file '%s': %s\n", path,
+ safe_strerror(errno));
+ outputfile = stdout;
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_vtysh_output_file,
+ no_vtysh_output_file_cmd,
+ "no output file [FILE]",
+ NO_STR
+ "Direct vtysh output to file\n"
+ "Direct vtysh output to file\n"
+ "Path to dump output to\n")
+{
+ if (outputfile != stdout) {
+ fclose(outputfile);
+ outputfile = stdout;
+ }
+ return CMD_SUCCESS;
+}
+
DEFUN(find,
find_cmd,
"find COMMAND...",
@@ -2736,6 +2786,8 @@ static void vtysh_install_default(enum node_type node)
{
install_element(node, &config_list_cmd);
install_element(node, &find_cmd);
+ install_element(node, &vtysh_output_file_cmd);
+ install_element(node, &no_vtysh_output_file_cmd);
}
/* Making connection to protocol daemon. */
@@ -2964,6 +3016,12 @@ static const struct cmd_variable_handler vtysh_var_handler[] = {
.completions = vtysh_autocomplete},
{.completions = NULL}};
+void vtysh_uninit()
+{
+ if (outputfile != stdout)
+ fclose(outputfile);
+}
+
void vtysh_init_vty(void)
{
/* Make vty structure. */
@@ -2971,6 +3029,9 @@ void vtysh_init_vty(void)
vty->type = VTY_SHELL;
vty->node = VIEW_NODE;
+ /* set default output */
+ outputfile = stdout;
+
/* Initialize commands. */
cmd_init(0);
cmd_variable_handler_register(vtysh_var_handler);