]> git.proxmox.com Git - mirror_frr.git/blobdiff - vtysh/vtysh.c
vtysh: add ability to output to file
[mirror_frr.git] / vtysh / vtysh.c
index 76343ded602cc0e6f053ddfa1642b75eee732316..9ec1ade0e3120ac26ca1d9c6782a61ecd006292d 100644 (file)
@@ -46,6 +46,9 @@
 
 DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy")
 
+/* Destination for vtysh output */
+FILE *outputfile;
+
 /* Struct VTY. */
 struct vty *vty;
 
@@ -375,21 +378,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 +408,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 +458,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 +540,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 +561,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 +569,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 +612,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 +670,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 +689,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 +752,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 +1857,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 +1878,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 +1908,7 @@ DEFUN (vtysh_show_work_queues_daemon,
        }
 
        ret = vtysh_client_execute(&vtysh_client[i], "show work-queues\n",
-                                  stdout);
+                                  outputfile);
 
        return ret;
 }
@@ -1932,9 +1935,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 +2229,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 +2253,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 +2262,7 @@ DEFUN (vtysh_write_terminal,
                fp = NULL;
        }
 
-       vty_out(vty, "end\n");
+       fprintf(outputfile, "end\n");
        return CMD_SUCCESS;
 }
 
@@ -2429,7 +2431,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 +2443,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 +2454,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 +2486,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 +2529,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 +2705,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 +2770,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 +3000,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 +3013,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);