]> git.proxmox.com Git - mirror_frr.git/commitdiff
vtysh: add | support
authorQuentin Young <qlyoung@cumulusnetworks.com>
Mon, 14 May 2018 22:13:03 +0000 (18:13 -0400)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Wed, 6 Jun 2018 16:16:10 +0000 (16:16 +0000)
* Rewrite pager implementation
* Replace fprintf() with vty_out()
* Modify vty_out() for better vtysh support
* Remove static global outputfile var
* Remove fp argument from many vtysh functions
* Add some docs for stuff along the way

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

index 5b2783d326524182a790105df97a2cf4b8d3f313..c04360f28e6724e0662ced2ac2916004545ae329 100644 (file)
@@ -1202,8 +1202,8 @@ static int handle_pipe_action(struct vty *vty, const char *cmd_in,
                        vty_out(vty, "%% Bad regexp '%s'", regexp);
                        goto fail;
                }
-               cmd_out = XSTRDUP(MTYPE_TMP, cmd_in);
-               *(strstr(cmd_in, "|")) = '\0';
+               *cmd_out = XSTRDUP(MTYPE_TMP, cmd_in);
+               *(strstr(*cmd_out, "|")) = '\0';
        } else {
                vty_out(vty, "%% Unknown action '%s'", token);
                goto fail;
index 3c38270a1dfe9e435c3021dc068140eb2c794646..b527827b342ca923c9915f496b9864807590406a 100644 (file)
@@ -139,3 +139,13 @@ void frrstr_strvec_free(vector v)
        vector_free(v);
 }
 
+bool begins_with(const char *str, const char *prefix)
+{
+       if (!str || !prefix)
+               return 0;
+       size_t lenstr = strlen(str);
+       size_t lenprefix = strlen(prefix);
+       if (lenprefix > lenstr)
+               return 0;
+       return strncmp(str, prefix, lenprefix) == 0;
+}
index f5edbf7b460824e30553dee8be75bfa693469b22..24547711221618a7c981ab9876ba99a3540183ee 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <sys/types.h>
 #include <regex.h>
+#include <stdbool.h>
 
 #include "vector.h"
 
@@ -82,5 +83,18 @@ void frrstr_filter_vec(vector v, regex_t *filter);
  */
 void frrstr_strvec_free(vector v);
 
+/*
+ * Prefix match for string.
+ *
+ * str
+ *    string to check for prefix match
+ *
+ * prefix
+ *    prefix to look for
+ *
+ * Returns:
+ *   true str starts with prefix, false otherwise
+ */
+bool begins_with(const char *str, const char *prefix);
 
 #endif /* _FRRSTR_H_ */
index 5a30bfa8adf3d3394fc65b34f146de5132cf1766..e4315e2d1c9c2552b4e47e505a5eb70d36a513cd 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -153,69 +153,73 @@ int vty_out(struct vty *vty, const char *format, ...)
                vty_out(vty, "%s", vty->frame);
        }
 
-       if (vty_shell(vty)) {
-               va_start(args, format);
-               vprintf(format, args);
-               va_end(args);
-       } else {
-               /* Try to write to initial buffer.  */
-               va_start(args, format);
-               len = vsnprintf(buf, sizeof(buf), format, args);
-               va_end(args);
-
-               /* Initial buffer is not enough.  */
-               if (len < 0 || len >= size) {
-                       while (1) {
-                               if (len > -1)
-                                       size = len + 1;
-                               else
-                                       size = size * 2;
-
-                               p = XREALLOC(MTYPE_VTY_OUT_BUF, p, size);
-                               if (!p)
-                                       return -1;
-
-                               va_start(args, format);
-                               len = vsnprintf(p, size, format, args);
-                               va_end(args);
-
-                               if (len > -1 && len < size)
-                                       break;
-                       }
-               }
+       /* Try to write to initial buffer.  */
+       va_start(args, format);
+       len = vsnprintf(buf, sizeof(buf), format, args);
+       va_end(args);
 
-               /* When initial buffer is enough to store all output.  */
-               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;
+       /* Initial buffer is not enough.  */
+       if (len < 0 || len >= size) {
+               while (1) {
+                       if (len > -1)
+                               size = len + 1;
+                       else
+                               size = size * 2;
+
+                       p = XREALLOC(MTYPE_VTY_OUT_BUF, p, size);
+                       if (!p)
+                               return -1;
+
+                       va_start(args, format);
+                       len = vsnprintf(p, size, format, args);
+                       va_end(args);
+
+                       if (len > -1 && len < size)
+                               break;
                }
+       }
 
-               /* Pointer p must point out buffer. */
-               if (vty->type != VTY_TERM)
-                       buffer_put(vty->obuf, (uint8_t *)filtered,
-                                  strlen(filtered));
-               else
-                       buffer_put_crlf(vty->obuf, (uint8_t *)filtered,
-                                       strlen(filtered));
+       /* When initial buffer is enough to store all output.  */
+       if (!p)
+               p = buf;
 
-               if (vty->filter)
-                       XFREE(MTYPE_TMP, filtered);
+       /* 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;
+       }
 
-               /* If p is not different with buf, it is allocated buffer.  */
-               if (p != buf)
-                       XFREE(MTYPE_VTY_OUT_BUF, p);
+       switch (vty->type) {
+       case VTY_TERM:
+               /* print with crlf replacement */
+               buffer_put_crlf(vty->obuf, (uint8_t *)filtered,
+                               strlen(filtered));
+               break;
+       case VTY_SHELL:
+               fprintf(vty->of, "%s", filtered);
+               fflush(vty->of);
+               break;
+       case VTY_SHELL_SERV:
+       case VTY_FILE:
+       default:
+               /* print without crlf replacement */
+               buffer_put(vty->obuf, (uint8_t *)filtered, strlen(filtered));
+               break;
        }
 
+       if (vty->filter)
+               XFREE(MTYPE_TMP, filtered);
+
+       /* If p is not different with buf, it is allocated buffer.  */
+       if (p != buf)
+               XFREE(MTYPE_VTY_OUT_BUF, p);
+
        return len;
 }
 
@@ -363,20 +367,6 @@ vty_dont_lflow_ahead (struct vty *vty)
 }
 #endif /* 0 */
 
-/* Allocate new vty struct. */
-struct vty *vty_new()
-{
-       struct vty *new = XCALLOC(MTYPE_VTY, sizeof(struct vty));
-
-       new->fd = new->wfd = -1;
-       new->obuf = buffer_new(0); /* Use default buffer size. */
-       new->buf = XCALLOC(MTYPE_VTY, VTY_BUFSIZ);
-       new->error_buf = XCALLOC(MTYPE_VTY, VTY_BUFSIZ);
-       new->max = VTY_BUFSIZ;
-
-       return new;
-}
-
 /* Authentication of vty */
 static void vty_auth(struct vty *vty, char *buf)
 {
@@ -1631,6 +1621,21 @@ static int vty_flush(struct thread *thread)
        return 0;
 }
 
+/* Allocate new vty struct. */
+struct vty *vty_new()
+{
+       struct vty *new = XCALLOC(MTYPE_VTY, sizeof(struct vty));
+
+       new->fd = new->wfd = -1;
+       new->obuf = buffer_new(0); /* Use default buffer size. */
+       new->buf = XCALLOC(MTYPE_VTY, VTY_BUFSIZ);
+       new->error_buf = XCALLOC(MTYPE_VTY, VTY_BUFSIZ);
+       new->max = VTY_BUFSIZ;
+
+       return new;
+}
+
+
 /* allocate and initialise vty */
 static struct vty *vty_new_init(int vty_sock)
 {
index 32fd471f18211b94ac131c6e1d942986268406f5..57b445ca687bfe4512b14c2b403d2e76464226d8 100644 (file)
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -41,6 +41,13 @@ struct vty {
        /* output FD, to support stdin/stdout combination */
        int wfd;
 
+       /* File output, used for VTYSH only */
+       FILE *of;
+       FILE *of_saved;
+
+       /* whether we are using pager or not */
+       bool is_paged;
+
        /* Is this vty connect to file or not */
        enum { VTY_TERM, VTY_FILE, VTY_SHELL, VTY_SHELL_SERV } type;
 
index 290d8f50e5e3c0d146b8d68501969626400d9ef2..cd47ef1c4538fa6ce64091792450d8cfc52d55d8 100644 (file)
 #include "vrf.h"
 #include "libfrr.h"
 #include "command_graph.h"
+#include "frrstr.h"
 
 DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy")
 
-/* Destination for vtysh output */
-FILE *outputfile;
-
 /* Struct VTY. */
 struct vty *vty;
 
 /* VTY shell pager name. */
 char *vtysh_pager_name = NULL;
 
-/* VTY shell client structure. */
+/* VTY shell client structure */
 struct vtysh_client {
        int fd;
        const char *name;
@@ -65,6 +63,57 @@ struct vtysh_client {
        struct vtysh_client *next;
 };
 
+/* Some utility functions for working on vtysh-specific vty tasks */
+
+static FILE *vty_open_pager(struct vty *vty)
+{
+       if (vty->is_paged)
+               return vty->of;
+
+       vty->of_saved = vty->of;
+       vty->of = popen(vtysh_pager_name, "w");
+       if (vty->of == NULL) {
+               vty->of = vty->of_saved;
+               perror("popen");
+               exit(1);
+       }
+
+       vty->is_paged = true;
+
+       return vty->of;
+}
+
+static int vty_close_pager(struct vty *vty)
+{
+       if (!vty->is_paged)
+               return 0;
+
+       fflush(vty->of);
+       if (pclose(vty->of) == -1) {
+               perror("pclose");
+               exit(1);
+       }
+
+       vty->of = vty->of_saved;
+       vty->is_paged = false;
+
+       return 0;
+}
+
+void vtysh_pager_init(void)
+{
+       char *pager_defined;
+
+       pager_defined = getenv("VTYSH_PAGER");
+
+       if (pager_defined)
+               vtysh_pager_name = strdup(pager_defined);
+       else
+               vtysh_pager_name = strdup(VTYSH_PAGER);
+}
+
+/* --- */
+
 struct vtysh_client vtysh_client[] = {
        {.fd = -1, .name = "zebra", .flag = VTYSH_ZEBRA, .next = NULL},
        {.fd = -1, .name = "ripd", .flag = VTYSH_RIPD, .next = NULL},
@@ -91,7 +140,7 @@ static int vtysh_reconnect(struct vtysh_client *vclient);
 static void vclient_close(struct vtysh_client *vclient)
 {
        if (vclient->fd >= 0) {
-               fprintf(stderr,
+               vty_out(vty,
                        "Warning: closing connection to %s because of an I/O error!\n",
                        vclient->name);
                close(vclient->fd);
@@ -100,21 +149,30 @@ static void vclient_close(struct vtysh_client *vclient)
        }
 }
 
-/* Return true if str begins with prefix, else return false */
-static int begins_with(const char *str, const char *prefix)
-{
-       if (!str || !prefix)
-               return 0;
-       size_t lenstr = strlen(str);
-       size_t lenprefix = strlen(prefix);
-       if (lenprefix > lenstr)
-               return 0;
-       return strncmp(str, prefix, lenprefix) == 0;
-}
-
+/*
+ * Send a CLI command to a client and read the response.
+ *
+ * Output will be printed to vty->of. If you want to suppress output, set that
+ * to NULL.
+ *
+ * vclient
+ *    the client to send the command to
+ *
+ * line
+ *    the command to send
+ *
+ * callback
+ *    if non-null, this will be called with each line of output received from
+ *    the client passed in the second parameter
+ *
+ * cbarg
+ *    optional first argument to pass to callback
+ *
+ * Returns:
+ *    a status code
+ */
 static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
-                           FILE *fp, void (*callback)(void *, const char *),
-                           void *cbarg)
+                           void (*callback)(void *, const char *), void *cbarg)
 {
        int ret;
        char stackbuf[4096];
@@ -155,7 +213,7 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
                        continue;
 
                if (nread <= 0) {
-                       fprintf(stderr, "vtysh: error reading from %s: %s (%d)",
+                       vty_out(vty, "vtysh: error reading from %s: %s (%d)",
                                vclient->name, safe_strerror(errno), errno);
                        goto out_err;
                }
@@ -227,12 +285,10 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
                        /* eol is at line end now, either \n => \0 or \0\0\0 */
                        assert(eol && eol <= bufvalid);
 
-                       if (fp) {
-                               fputs(buf, fp);
-                               fputc('\n', fp);
-                       }
-                       if (callback)
-                               callback(cbarg, buf);
+                       if (vty->of)
+                               vty_out(vty, "%s\n", buf);
+
+                       callback(cbarg, buf);
 
                        /* shift back data and adjust bufvalid */
                        memmove(buf, eol, bufvalid - eol);
@@ -243,8 +299,8 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
 
                /* else if no callback, dump raw */
                if (!callback) {
-                       if (fp)
-                               fwrite(buf, 1, textlen, fp);
+                       if (vty->of)
+                               vty_out(vty, "%s", buf);
                        memmove(buf, buf + textlen, bufvalid - buf - textlen);
                        bufvalid -= textlen;
                        if (end)
@@ -281,7 +337,7 @@ out:
 }
 
 static int vtysh_client_run_all(struct vtysh_client *head_client,
-                               const char *line, int continue_on_err, FILE *fp,
+                               const char *line, int continue_on_err,
                                void (*callback)(void *, const char *),
                                void *cbarg)
 {
@@ -290,7 +346,7 @@ static int vtysh_client_run_all(struct vtysh_client *head_client,
        int correct_instance = 0, wrong_instance = 0;
 
        for (client = head_client; client; client = client->next) {
-               rc = vtysh_client_run(client, line, fp, callback, cbarg);
+               rc = vtysh_client_run(client, line, callback, cbarg);
                if (rc == CMD_NOT_MY_INSTANCE) {
                        wrong_instance++;
                        continue;
@@ -303,8 +359,8 @@ static int vtysh_client_run_all(struct vtysh_client *head_client,
                        rc_all = rc;
                }
        }
-       if (wrong_instance && !correct_instance && fp) {
-               fprintf(fp,
+       if (wrong_instance && !correct_instance) {
+               vty_out(vty,
                        "%% [%s]: command ignored as it targets an instance that is not running\n",
                        head_client->name);
                rc_all = CMD_WARNING_CONFIG_FAILED;
@@ -312,12 +368,34 @@ static int vtysh_client_run_all(struct vtysh_client *head_client,
        return rc_all;
 }
 
+/*
+ * Execute command against all daemons.
+ *
+ * head_client
+ *    where to start walking in the daemon list
+ *
+ * line
+ *    the specific command to execute
+ *
+ * Returns:
+ *    a status code
+ */
 static int vtysh_client_execute(struct vtysh_client *head_client,
-                               const char *line, FILE *fp)
+                               const char *line)
 {
-       return vtysh_client_run_all(head_client, line, 0, fp, NULL, NULL);
+       return vtysh_client_run_all(head_client, line, 0, NULL, NULL);
 }
 
+/*
+ * Retrieve all running config from daemons and parse it with the vtysh config
+ * parser. Returned output is not displayed to the user.
+ *
+ * head_client
+ *    where to start walking in the daemon list
+ *
+ * line
+ *    the specific command to execute
+ */
 static void vtysh_client_config(struct vtysh_client *head_client, char *line)
 {
        /* watchfrr currently doesn't load any config, and has some hardcoded
@@ -327,20 +405,12 @@ static void vtysh_client_config(struct vtysh_client *head_client, char *line)
        if (head_client->flag == VTYSH_WATCHFRR)
                return;
 
-       vtysh_client_run_all(head_client, line, 1, NULL,
-                            vtysh_config_parse_line, NULL);
-}
-
-void vtysh_pager_init(void)
-{
-       char *pager_defined;
-
-       pager_defined = getenv("VTYSH_PAGER");
-
-       if (pager_defined)
-               vtysh_pager_name = strdup(pager_defined);
-       else
-               vtysh_pager_name = strdup(VTYSH_PAGER);
+       /* suppress output to user */
+       vty->of_saved = vty->of;
+       vty->of = NULL;
+       vtysh_client_run_all(head_client, line, 1, vtysh_config_parse_line,
+                            NULL);
+       vty->of = vty->of_saved;
 }
 
 /* Command execution over the vty interface. */
@@ -350,8 +420,6 @@ static int vtysh_execute_func(const char *line, int pager)
        unsigned int i;
        vector vline;
        const struct cmd_element *cmd;
-       FILE *fp = NULL;
-       int closepager = 0;
        int tried = 0;
        int saved_ret, saved_node;
 
@@ -364,12 +432,12 @@ static int vtysh_execute_func(const char *line, int pager)
        if (user_mode) {
                if (strncmp("en", vector_slot(vline, 0), 2) == 0) {
                        cmd_free_strvec(vline);
-                       fprintf(stdout, "%% Command not allowed: enable\n");
+                       vty_out(vty, "%% Command not allowed: enable\n");
                        return CMD_WARNING;
                }
        }
 
-       saved_ret = ret = cmd_execute_command(vline, vty, &cmd, 1);
+       saved_ret = ret = cmd_execute(vty, line, &cmd, 1);
        saved_node = vty->node;
 
        /*
@@ -381,7 +449,7 @@ static int vtysh_execute_func(const char *line, int pager)
               && ret != CMD_WARNING && ret != CMD_WARNING_CONFIG_FAILED
               && vty->node > CONFIG_NODE) {
                vty->node = node_parent(vty->node);
-               ret = cmd_execute_command(vline, vty, &cmd, 1);
+               ret = cmd_execute(vty, line, &cmd, 1);
                tried++;
        }
 
@@ -445,16 +513,16 @@ static int vtysh_execute_func(const char *line, int pager)
        case CMD_WARNING:
        case CMD_WARNING_CONFIG_FAILED:
                if (vty->type == VTY_FILE)
-                       fprintf(stdout, "Warning...\n");
+                       vty_out(vty, "Warning...\n");
                break;
        case CMD_ERR_AMBIGUOUS:
-               fprintf(stdout, "%% Ambiguous command: %s\n", line);
+               vty_out(vty, "%% Ambiguous command: %s\n", line);
                break;
        case CMD_ERR_NO_MATCH:
-               fprintf(stdout, "%% Unknown command: %s\n", line);
+               vty_out(vty, "%% Unknown command: %s\n", line);
                break;
        case CMD_ERR_INCOMPLETE:
-               fprintf(stdout, "%% Command incomplete: %s\n", line);
+               vty_out(vty, "%% Command incomplete: %s\n", line);
                break;
        case CMD_SUCCESS_DAEMON: {
                /*
@@ -462,21 +530,13 @@ static int vtysh_execute_func(const char *line, int pager)
                 * 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 = outputfile;
-                       } else
-                               closepager = 1;
-               }
+               if (pager && strncmp(line, "exit", 4))
+                       vty_open_pager(vty);
 
                if (!strcmp(cmd->string, "configure terminal")) {
                        for (i = 0; i < array_size(vtysh_client); i++) {
                                cmd_stat = vtysh_client_execute(
-                                       &vtysh_client[i], line, fp);
+                                       &vtysh_client[i], line);
                                if (cmd_stat == CMD_WARNING)
                                        break;
                        }
@@ -485,14 +545,8 @@ static int vtysh_execute_func(const char *line, int pager)
                                line = "end";
                                vline = cmd_make_strvec(line);
 
-                               if (vline == NULL) {
-                                       if (pager && vtysh_pager_name && fp
-                                           && fp != outputfile && closepager) {
-                                               if (pclose(fp) == -1) {
-                                                       perror("pclose failed for pager");
-                                               }
-                                               fp = NULL;
-                                       }
+                               if (vline == NULL && vty->is_paged) {
+                                       vty_close_pager(vty);
                                        return CMD_SUCCESS;
                                }
 
@@ -532,7 +586,7 @@ static int vtysh_execute_func(const char *line, int pager)
                                        }
                                }
                                cmd_stat = vtysh_client_execute(
-                                       &vtysh_client[i], line, fp);
+                                       &vtysh_client[i], line);
                                if (cmd_stat != CMD_SUCCESS)
                                        break;
                        }
@@ -544,12 +598,9 @@ static int vtysh_execute_func(const char *line, int pager)
                        (*cmd->func)(cmd, vty, 0, NULL);
        }
        }
-       if (pager && vtysh_pager_name && fp && closepager && fp != outputfile) {
-               if (pclose(fp) == -1) {
-                       perror("pclose failed for pager");
-               }
-               fp = NULL;
-       }
+       if (vty->is_paged)
+               vty_close_pager(vty);
+
        return cmd_stat;
 }
 
@@ -626,19 +677,19 @@ int vtysh_mark_file(const char *filename)
                switch (vty->node) {
                case LDP_IPV4_IFACE_NODE:
                        if (strncmp(vty_buf_copy, "   ", 3)) {
-                               fprintf(outputfile, "  end\n");
+                               vty_out(vty, "  end\n");
                                vty->node = LDP_IPV4_NODE;
                        }
                        break;
                case LDP_IPV6_IFACE_NODE:
                        if (strncmp(vty_buf_copy, "   ", 3)) {
-                               fprintf(outputfile, "  end\n");
+                               vty_out(vty, "  end\n");
                                vty->node = LDP_IPV6_NODE;
                        }
                        break;
                case LDP_PSEUDOWIRE_NODE:
                        if (strncmp(vty_buf_copy, "  ", 2)) {
-                               fprintf(outputfile, " end\n");
+                               vty_out(vty, " end\n");
                                vty->node = LDP_L2VPN_NODE;
                        }
                        break;
@@ -647,7 +698,7 @@ int vtysh_mark_file(const char *filename)
                }
 
                if (vty_buf_trimmed[0] == '!' || vty_buf_trimmed[0] == '#') {
-                       fprintf(outputfile, "%s", vty->buf);
+                       vty_out(vty, "%s", vty->buf);
                        continue;
                }
 
@@ -655,7 +706,7 @@ int vtysh_mark_file(const char *filename)
                vline = cmd_make_strvec(vty->buf);
 
                if (vline == NULL) {
-                       fprintf(outputfile, "%s", vty->buf);
+                       vty_out(vty, "%s", vty->buf);
                        continue;
                }
 
@@ -704,15 +755,15 @@ int vtysh_mark_file(const char *filename)
                             || prev_node == BGP_IPV6M_NODE
                             || prev_node == BGP_EVPN_NODE)
                            && (tried == 1)) {
-                               fprintf(outputfile, "exit-address-family\n");
+                               vty_out(vty, "exit-address-family\n");
                        } else if ((prev_node == BGP_EVPN_VNI_NODE)
                                   && (tried == 1)) {
-                               fprintf(outputfile, "exit-vni\n");
+                               vty_out(vty, "exit-vni\n");
                        } else if ((prev_node == KEYCHAIN_KEY_NODE)
                                   && (tried == 1)) {
-                               fprintf(outputfile, "exit\n");
+                               vty_out(vty, "exit\n");
                        } else if (tried) {
-                               fprintf(outputfile, "end\n");
+                               vty_out(vty, "end\n");
                        }
                }
                /*
@@ -757,22 +808,14 @@ int vtysh_mark_file(const char *filename)
                        XFREE(MTYPE_VTYSH_CMD, vty_buf_copy);
                        return CMD_ERR_INCOMPLETE;
                case CMD_SUCCESS:
-                       fprintf(stdout, "%s", vty->buf);
+                       vty_out(vty, "%s", vty->buf);
                        break;
                case CMD_SUCCESS_DAEMON: {
-                       unsigned int i;
                        int cmd_stat = CMD_SUCCESS;
 
-                       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,
-                                               outputfile);
-                                       if (cmd_stat != CMD_SUCCESS)
-                                               break;
-                               }
-                       }
+                       vty_out(vty, "%s", vty->buf);
+                       cmd_stat = vtysh_client_execute(&vtysh_client[0],
+                                                       vty->buf);
                        if (cmd_stat != CMD_SUCCESS)
                                break;
 
@@ -782,7 +825,7 @@ int vtysh_mark_file(const char *filename)
                }
        }
        /* This is the end */
-       fprintf(outputfile, "\nend\n");
+       vty_out(vty, "\nend\n");
        vty_close(vty);
        XFREE(MTYPE_VTYSH_CMD, vty_buf_copy);
 
@@ -839,8 +882,7 @@ int vtysh_config_from_file(struct vty *vty, FILE *fp)
                        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,
-                                               outputfile);
+                                               &vtysh_client[i], vty->buf);
                                        /*
                                         * CMD_WARNING - Can mean that the
                                         * command was parsed successfully but
@@ -904,14 +946,16 @@ static int vtysh_process_questionmark(const char *input, int input_len)
        case CMD_ERR_AMBIGUOUS:
                cmd_free_strvec(vline);
                vector_free(describe);
-               fprintf(stdout, "%% Ambiguous command.\n");
+               vty_out(vty, "%% Ambiguous command.\n");
+               rl_on_new_line();
                return 0;
                break;
        case CMD_ERR_NO_MATCH:
                cmd_free_strvec(vline);
                if (describe)
                        vector_free(describe);
-               fprintf(stdout, "%% There is no matched command.\n");
+               vty_out(vty, "%% There is no matched command.\n");
+               rl_on_new_line();
                return 0;
                break;
        }
@@ -932,10 +976,10 @@ static int vtysh_process_questionmark(const char *input, int input_len)
        for (i = 0; i < vector_active(describe); i++)
                if ((token = vector_slot(describe, i)) != NULL) {
                        if (!token->desc)
-                               fprintf(stdout, "  %-s\n", token->text);
+                               vty_out(vty, "  %-s\n", token->text);
                        else
-                               fprintf(stdout, "  %-*s  %s\n", width,
-                                       token->text, token->desc);
+                               vty_out(vty, "  %-*s  %s\n", width, token->text,
+                                       token->desc);
 
                        if (IS_VARYING_TOKEN(token->type)) {
                                const char *ref = vector_slot(
@@ -950,7 +994,7 @@ static int vtysh_process_questionmark(const char *input, int input_len)
 
                                        char *ac = cmd_variable_comp2str(
                                                varcomps, cols);
-                                       fprintf(stdout, "%s\n", ac);
+                                       vty_out(vty, "%s\n", ac);
                                        XFREE(MTYPE_TMP, ac);
                                }
 
@@ -973,7 +1017,7 @@ static int vtysh_rl_describe(void)
 {
        int ret;
 
-       fprintf(stdout, "\n");
+       vty_out(vty, "\n");
 
        ret = vtysh_process_questionmark(rl_line_buffer, rl_end);
        rl_on_new_line();
@@ -2106,11 +2150,10 @@ DEFUN (vtysh_show_thread,
        snprintf(line, sizeof(line), "do show thread cpu %s\n", filter);
        for (i = 0; i < array_size(vtysh_client); i++)
                if (vtysh_client[i].fd >= 0) {
-                       fprintf(stdout, "Thread statistics for %s:\n",
+                       vty_out(vty, "Thread statistics for %s:\n",
                                vtysh_client[i].name);
-                       ret = vtysh_client_execute(&vtysh_client[i], line,
-                                                  outputfile);
-                       fprintf(stdout, "\n");
+                       ret = vtysh_client_execute(&vtysh_client[i], line);
+                       vty_out(vty, "\n");
                }
        return ret;
 }
@@ -2127,11 +2170,10 @@ DEFUN (vtysh_show_work_queues,
 
        for (i = 0; i < array_size(vtysh_client); i++)
                if (vtysh_client[i].fd >= 0) {
-                       fprintf(stdout, "Work queue statistics for %s:\n",
+                       vty_out(vty, "Work queue statistics for %s:\n",
                                vtysh_client[i].name);
-                       ret = vtysh_client_execute(&vtysh_client[i], line,
-                                                  outputfile);
-                       fprintf(stdout, "\n");
+                       ret = vtysh_client_execute(&vtysh_client[i], line);
+                       vty_out(vty, "\n");
                }
 
        return ret;
@@ -2160,8 +2202,7 @@ DEFUN (vtysh_show_work_queues_daemon,
                        break;
        }
 
-       ret = vtysh_client_execute(&vtysh_client[i], "show work-queues\n",
-                                  outputfile);
+       ret = vtysh_client_execute(&vtysh_client[i], "show work-queues\n");
 
        return ret;
 }
@@ -2188,10 +2229,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(outputfile, headline, vtysh_client[i].name);
-                       ret = vtysh_client_execute(&vtysh_client[i], line,
-                                                  outputfile);
-                       fprintf(stdout, "\n");
+                       vty_out(vty, headline, vtysh_client[i].name);
+                       ret = vtysh_client_execute(&vtysh_client[i], line);
+                       vty_out(vty, "\n");
                }
 
        return ret;
@@ -2225,16 +2265,16 @@ DEFUN (vtysh_show_debugging_hashtable,
        "Statistics about hash tables\n"
        "Statistics about hash tables\n")
 {
-       fprintf(stdout, "\n");
-       fprintf(stdout,
+       vty_out(vty, "\n");
+       vty_out(vty,
                "Load factor (LF) - average number of elements across all buckets\n");
-       fprintf(stdout,
+       vty_out(vty,
                "Full load factor (FLF) - average number of elements across full buckets\n\n");
-       fprintf(stdout,
+       vty_out(vty,
                "Standard deviation (SD) is calculated for both the LF and FLF\n");
-       fprintf(stdout,
+       vty_out(vty,
                "and indicates the typical deviation of bucket chain length\n");
-       fprintf(stdout, "from the value in the corresponding load factor.\n\n");
+       vty_out(vty, "from the value in the corresponding load factor.\n\n");
 
        return show_per_daemon("do show debugging hashtable\n",
                               "Hashtable statistics for %s:\n");
@@ -2499,19 +2539,10 @@ DEFUN (vtysh_write_terminal,
 {
        unsigned int i;
        char line[] = "do write terminal\n";
-       FILE *fp = outputfile;
-
-       if (fp == stdout && vtysh_pager_name) {
-               fp = popen(vtysh_pager_name, "w");
-               if (fp == NULL) {
-                       perror("popen");
-                       exit(1);
-               }
-       }
 
-       fprintf(outputfile, "Building configuration...\n");
-       fprintf(outputfile, "\nCurrent configuration:\n");
-       fprintf(outputfile, "!\n");
+       vty_out(vty, "Building configuration...\n");
+       vty_out(vty, "\nCurrent configuration:\n");
+       vty_out(vty, "!\n");
 
        for (i = 0; i < array_size(vtysh_client); i++)
                if ((argc < 3)
@@ -2519,20 +2550,12 @@ DEFUN (vtysh_write_terminal,
                        vtysh_client_config(&vtysh_client[i], line);
 
        /* Integrate vtysh specific configuration. */
+       vty_open_pager(vty);
        vtysh_config_write();
+       vtysh_config_dump();
+       vty_close_pager(vty);
+       vty_out(vty, "end\n");
 
-       vtysh_config_dump(fp);
-
-       if (vtysh_pager_name && fp != outputfile) {
-               fflush(fp);
-               if (pclose(fp) == -1) {
-                       perror("pclose");
-                       exit(1);
-               }
-               fp = NULL;
-       }
-
-       fprintf(outputfile, "end\n");
        return CMD_SUCCESS;
 }
 
@@ -2602,12 +2625,12 @@ int vtysh_write_config_integrated(void)
        struct stat st;
        int err = 0;
 
-       fprintf(stdout, "Building Configuration...\n");
+       vty_out(vty, "Building Configuration...\n");
 
        backup_config_file(frr_config);
        fp = fopen(frr_config, "w");
        if (fp == NULL) {
-               fprintf(stdout,
+               vty_out(vty,
                        "%% Error: failed to open configuration file %s: %s\n",
                        frr_config, safe_strerror(errno));
                return CMD_WARNING_CONFIG_FAILED;
@@ -2618,7 +2641,7 @@ int vtysh_write_config_integrated(void)
                vtysh_client_config(&vtysh_client[i], line);
 
        vtysh_config_write();
-       vtysh_config_dump(fp);
+       vtysh_config_dump();
 
        if (fchmod(fd, CONFIGFILE_MASK) != 0) {
                printf("%% Warning: can't chmod configuration file %s: %s\n",
@@ -2701,8 +2724,7 @@ DEFUN (vtysh_write_memory,
        char line[] = "do write memory\n";
        unsigned int i;
 
-       fprintf(outputfile,
-               "Note: this version of vtysh never writes vtysh.conf\n");
+       vty_out(vty, "Note: this version of vtysh never writes vtysh.conf\n");
 
        /* If integrated frr.conf explicitely set. */
        if (want_config_integrated()) {
@@ -2717,8 +2739,7 @@ DEFUN (vtysh_write_memory,
                if (i < array_size(vtysh_client) && vtysh_client[i].fd != -1) {
                        used_watchfrr = true;
                        ret = vtysh_client_execute(&vtysh_client[i],
-                                                  "do write integrated",
-                                                  outputfile);
+                                                  "do write integrated");
                }
 
                /*
@@ -2734,10 +2755,10 @@ DEFUN (vtysh_write_memory,
                return ret;
        }
 
-       fprintf(outputfile, "Building Configuration...\n");
+       vty_out(vty, "Building Configuration...\n");
 
        for (i = 0; i < array_size(vtysh_client); i++)
-               ret = vtysh_client_execute(&vtysh_client[i], line, outputfile);
+               ret = vtysh_client_execute(&vtysh_client[i], line);
 
        return ret;
 }
@@ -2766,7 +2787,7 @@ DEFUN (vtysh_terminal_length,
 
        lines = strtol(argv[idx_number]->arg, &endptr, 10);
        if (lines < 0 || lines > 512 || *endptr != '\0') {
-               fprintf(outputfile, "length is malformed\n");
+               vty_out(vty, "length is malformed\n");
                return CMD_WARNING;
        }
 
@@ -2809,8 +2830,8 @@ DEFUN (vtysh_show_daemons,
 
        for (i = 0; i < array_size(vtysh_client); i++)
                if (vtysh_client[i].fd >= 0)
-                       fprintf(outputfile, " %s", vtysh_client[i].name);
-       fprintf(outputfile, "\n");
+                       vty_out(vty, " %s", vtysh_client[i].name);
+       vty_out(vty, "\n");
 
        return CMD_SUCCESS;
 }
@@ -3007,11 +3028,11 @@ DEFUN (vtysh_output_file,
        "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,
+       vty->of = fopen(path, "a");
+       if (!vty->of) {
+               vty_out(vty, "Failed to open file '%s': %s\n", path,
                        safe_strerror(errno));
-               outputfile = stdout;
+               vty->of = stdout;
        }
        return CMD_SUCCESS;
 }
@@ -3024,9 +3045,9 @@ DEFUN (no_vtysh_output_file,
        "Direct vtysh output to file\n"
        "Path to dump output to\n")
 {
-       if (outputfile != stdout) {
-               fclose(outputfile);
-               outputfile = stdout;
+       if (vty->of != stdout) {
+               fclose(vty->of);
+               vty->of = stdout;
        }
        return CMD_SUCCESS;
 }
@@ -3050,7 +3071,7 @@ DEFUN(find,
                for (unsigned int j = 0; j < vector_active(clis); j++) {
                        cli = vector_slot(clis, j);
                        if (strcasestr(cli->string, text))
-                               fprintf(stdout, "  (%s)  %s\n",
+                               vty_out(vty, "  (%s)  %s\n",
                                        node_names[node->node], cli->string);
                }
        }
@@ -3157,7 +3178,7 @@ static int vtysh_reconnect(struct vtysh_client *vclient)
                return ret;
        }
        fprintf(stderr, "success!\n");
-       if (vtysh_client_execute(vclient, "enable", NULL) < 0)
+       if (vtysh_client_execute(vclient, "enable") < 0)
                return -1;
        return vtysh_execute_no_pager("end");
 }
@@ -3315,8 +3336,8 @@ static void vtysh_autocomplete(vector comps, struct cmd_token *token)
                 token->text, token->varname ? token->varname : "-");
 
        for (i = 0; i < array_size(vtysh_client); i++)
-               vtysh_client_run_all(&vtysh_client[i], accmd, 1, NULL,
-                                    vtysh_ac_line, comps);
+               vtysh_client_run_all(&vtysh_client[i], accmd, 1, vtysh_ac_line,
+                                    comps);
 }
 
 static const struct cmd_variable_handler vtysh_var_handler[] = {
@@ -3328,8 +3349,8 @@ static const struct cmd_variable_handler vtysh_var_handler[] = {
 
 void vtysh_uninit()
 {
-       if (outputfile != stdout)
-               fclose(outputfile);
+       if (vty->of != stdout)
+               fclose(vty->of);
 }
 
 void vtysh_init_vty(void)
@@ -3340,7 +3361,7 @@ void vtysh_init_vty(void)
        vty->node = VIEW_NODE;
 
        /* set default output */
-       outputfile = stdout;
+       vty->of = stdout;
 
        /* Initialize commands. */
        cmd_init(0);
index cbfc1b5b232ab34e37679683f218619d5ce30788..6fa61dd883683d71c085d0b4c41cb813c460bf8d 100644 (file)
@@ -90,7 +90,7 @@ int vtysh_write_config_integrated(void);
 
 void vtysh_config_parse_line(void *, const char *);
 
-void vtysh_config_dump(FILE *);
+void vtysh_config_dump(void);
 
 void vtysh_config_init(void);
 
index 6f3b6a826751cbe02b46db8fc877adafc7416769..93210c2a7fe565e5641fd5db214a841fd27f8476 100644 (file)
@@ -342,7 +342,7 @@ void vtysh_config_parse_line(void *arg, const char *line)
         || (I) == MPLS_NODE)
 
 /* Display configuration to file pointer. */
-void vtysh_config_dump(FILE *fp)
+void vtysh_config_dump()
 {
        struct listnode *node, *nnode;
        struct listnode *mnode, *mnnode;
@@ -351,12 +351,10 @@ void vtysh_config_dump(FILE *fp)
        char *line;
        unsigned int i;
 
-       for (ALL_LIST_ELEMENTS(config_top, node, nnode, line)) {
-               fprintf(fp, "%s\n", line);
-               fflush(fp);
-       }
-       fprintf(fp, "!\n");
-       fflush(fp);
+       for (ALL_LIST_ELEMENTS(config_top, node, nnode, line))
+               vty_out(vty, "%s\n", line);
+
+       vty_out(vty, "!\n");
 
        for (i = 0; i < vector_active(configvec); i++)
                if ((master = vector_slot(configvec, i)) != NULL) {
@@ -373,23 +371,16 @@ void vtysh_config_dump(FILE *fp)
                                    && list_isempty(config->line))
                                        continue;
 
-                               fprintf(fp, "%s\n", config->name);
-                               fflush(fp);
+                               vty_out(vty, "%s\n", config->name);
 
                                for (ALL_LIST_ELEMENTS(config->line, mnode,
-                                                      mnnode, line)) {
-                                       fprintf(fp, "%s\n", line);
-                                       fflush(fp);
-                               }
-                               if (!NO_DELIMITER(i)) {
-                                       fprintf(fp, "!\n");
-                                       fflush(fp);
-                               }
-                       }
-                       if (NO_DELIMITER(i)) {
-                               fprintf(fp, "!\n");
-                               fflush(fp);
+                                                      mnnode, line))
+                                       vty_out(vty, "%s\n", line);
+                               if (!NO_DELIMITER(i))
+                                       vty_out(vty, "!\n");
                        }
+                       if (NO_DELIMITER(i))
+                               vty_out(vty, "!\n");
                }
 
        for (i = 0; i < vector_active(configvec); i++)