diff options
author | Donald Sharp <sharpd@cumulusnetworks.com> | 2015-05-20 03:04:11 +0200 |
---|---|---|
committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2015-05-20 03:04:11 +0200 |
commit | 0846286b096be2cf437a9b95eb4c484156806df3 (patch) | |
tree | 37db69c3424415e3e0a0c25df7480fb876f11240 /vtysh | |
parent | Zebra: Fix multiple RNH deletes (diff) | |
download | frr-0846286b096be2cf437a9b95eb4c484156806df3.tar.xz frr-0846286b096be2cf437a9b95eb4c484156806df3.zip |
vtysh-add-mark-cmd.patch
VTYSH: Add support for marking a file with appropriate end of context
To support applying only differences to the existing config, this patch
enables supplying the appropriate end markers to a provided file (or
stdin). By end markers, I mean, adding "end" and "exit-address-family"
at the appropriate places in the configuration to ease finding the
differences with the running configuration.
Diffstat (limited to 'vtysh')
-rw-r--r-- | vtysh/vtysh.c | 161 | ||||
-rw-r--r-- | vtysh/vtysh.h | 2 | ||||
-rw-r--r-- | vtysh/vtysh_main.c | 42 |
3 files changed, 199 insertions, 6 deletions
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 2534e8ae1..a3a39d8e2 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -500,6 +500,157 @@ vtysh_execute (const char *line) return vtysh_execute_func (line, 1); } +int +vtysh_mark_file (char *filename) +{ + struct vty *vty; + FILE *confp = NULL; + int ret; + vector vline; + int tried = 0; + struct cmd_element *cmd; + int saved_ret, prev_node; + int lineno = 0; + + if (strncmp("-", filename, 1) == 0) + confp = stdin; + else + confp = fopen (filename, "r"); + + if (confp == NULL) + return (1); + + vty = vty_new (); + vty->fd = 0; /* stdout */ + vty->type = VTY_TERM; + vty->node = CONFIG_NODE; + + vtysh_execute_no_pager ("enable"); + vtysh_execute_no_pager ("configure terminal"); + + while (fgets (vty->buf, VTY_BUFSIZ, confp)) + { + lineno++; + tried = 0; + + if (vty->buf[0] == '!' || vty->buf[1] == '#') + { + fprintf(stdout, "%s", vty->buf); + continue; + } + + /* Split readline string up into the vector. */ + vline = cmd_make_strvec (vty->buf); + + if (vline == NULL) + { + fprintf(stdout, "%s", vty->buf); + continue; + } + + prev_node = vty->node; + saved_ret = ret = cmd_execute_command_strict (vline, vty, &cmd); + + /* If command doesn't succeeded in current node, try to walk up in node tree. + * Changing vty->node is enough to try it just out without actual walkup in + * the vtysh. */ + while (ret != CMD_SUCCESS && ret != CMD_SUCCESS_DAEMON && ret != CMD_WARNING + && vty->node > CONFIG_NODE) + { + vty->node = node_parent(vty->node); + ret = cmd_execute_command_strict (vline, vty, &cmd); + tried++; + } + + /* If command succeeded in any other node than current (tried > 0) we have + * to move into node in the vtysh where it succeeded. */ + if (ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON || ret == CMD_WARNING) + { + if ((prev_node == BGP_VPNV4_NODE || prev_node == BGP_IPV4_NODE + || prev_node == BGP_IPV6_NODE || prev_node == BGP_IPV4M_NODE + || prev_node == BGP_IPV6M_NODE) + && (tried == 1)) + { + fprintf(stdout, "exit-address-family\n"); + } + else if ((prev_node == KEYCHAIN_KEY_NODE) && (tried == 1)) + { + fprintf(stdout, "exit\n"); + } + else if (tried) + { + fprintf(stdout, "end\n"); + } + } + /* If command didn't succeed in any node, continue with return value from + * first try. */ + else if (tried) + { + ret = saved_ret; + vty->node = prev_node; + } + + cmd_free_strvec (vline); + switch (ret) + { + case CMD_WARNING: + if (vty->type == VTY_FILE) + fprintf (stderr,"line %d: Warning...: %s\n", lineno, vty->buf); + fclose(confp); + vty_close(vty); + return (1); + case CMD_ERR_AMBIGUOUS: + fprintf (stderr,"line %d: %% Ambiguous command: %s\n", lineno, vty->buf); + fclose(confp); + vty_close(vty); + return(1); + case CMD_ERR_NO_MATCH: + fprintf (stderr,"line %d: %% Unknown command: %s\n", lineno, vty->buf); + fclose(confp); + vty_close(vty); + return(1); + case CMD_ERR_INCOMPLETE: + fprintf (stderr,"line %d: %% Command incomplete: %s\n", lineno, vty->buf); + fclose(confp); + vty_close(vty); + return(1); + case CMD_SUCCESS: + fprintf(stdout, "%s", vty->buf); + break; + case CMD_SUCCESS_DAEMON: + { + u_int i; + int cmd_stat = CMD_SUCCESS; + + fprintf(stdout, "%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); + if (cmd_stat != CMD_SUCCESS) + break; + } + } + if (cmd_stat != CMD_SUCCESS) + break; + + if (cmd->func) + (*cmd->func) (cmd, vty, 0, NULL); + } + } + } + /* This is the end */ + fprintf(stdout, "end\n"); + vty_close(vty); + + if (confp != stdin) + fclose(confp); + + return (0); +} + /* Configration make from file. */ int vtysh_config_from_file (struct vty *vty, FILE *fp) @@ -507,6 +658,7 @@ vtysh_config_from_file (struct vty *vty, FILE *fp) int ret; vector vline; struct cmd_element *cmd; + int save_node = CONFIG_NODE; while (fgets (vty->buf, VTY_BUFSIZ, fp)) { @@ -544,10 +696,15 @@ vtysh_config_from_file (struct vty *vty, FILE *fp) } else { + save_node = vty->node; vtysh_execute ("end"); vtysh_execute ("configure terminal"); vty->node = CONFIG_NODE; ret = cmd_execute_command_strict (vline, vty, &cmd); + if ((ret != CMD_SUCCESS) && + (ret != CMD_SUCCESS_DAEMON) && + (ret != CMD_WARNING)) + vty->node = save_node; } } @@ -560,13 +717,13 @@ vtysh_config_from_file (struct vty *vty, FILE *fp) fprintf (stdout,"Warning...\n"); break; case CMD_ERR_AMBIGUOUS: - fprintf (stdout,"%% Ambiguous command.\n"); + fprintf (stdout,"%% Ambiguous command: %s\n", vty->buf); break; case CMD_ERR_NO_MATCH: fprintf (stdout,"%% Unknown command: %s", vty->buf); break; case CMD_ERR_INCOMPLETE: - fprintf (stdout,"%% Command incomplete.\n"); + fprintf (stdout,"%% Command incomplete: %s\n", vty->buf); break; case CMD_SUCCESS_DAEMON: { diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 3cc7bafe0..c6430e10b 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -52,6 +52,8 @@ void vtysh_config_write (void); int vtysh_config_from_file (struct vty *, FILE *); +int vtysh_mark_file(char *filename); + int vtysh_read_config (char *); void vtysh_config_parse (char *); diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 48958f0f3..c706f154a 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -141,8 +141,10 @@ usage (int status) "-b, --boot Execute boot startup configuration\n" \ "-c, --command Execute argument as command\n" \ "-d, --daemon Connect only to the specified daemon\n" \ + "-f, --inputfile Execute commands from specific file and exit\n" \ "-E, --echo Echo prompt and command in -c mode\n" \ "-C, --dryrun Check configuration for validity and exit\n" \ + "-m, --markfile Mark input file with context end\n" "-h, --help Display this help and exit\n\n" \ "Note that multiple commands may be executed from the command\n" \ "line by passing multiple -c args, or by embedding linefeed\n" \ @@ -160,10 +162,12 @@ struct option longopts[] = { "eval", required_argument, NULL, 'e'}, { "command", required_argument, NULL, 'c'}, { "daemon", required_argument, NULL, 'd'}, + { "inputfile", required_argument, NULL, 'f'}, { "echo", no_argument, NULL, 'E'}, { "dryrun", no_argument, NULL, 'C'}, { "help", no_argument, NULL, 'h'}, { "noerror", no_argument, NULL, 'n'}, + { "mark", no_argument, NULL, 'm'}, { 0 } }; @@ -219,6 +223,7 @@ main (int argc, char **argv, char **env) int dryrun = 0; int boot_flag = 0; const char *daemon_name = NULL; + const char *inputfile = NULL; struct cmd_rec { const char *line; struct cmd_rec *next; @@ -226,6 +231,7 @@ main (int argc, char **argv, char **env) struct cmd_rec *tail = NULL; int echo_command = 0; int no_error = 0; + int markfile = 0; /* Preserve name of myself. */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); @@ -237,7 +243,7 @@ main (int argc, char **argv, char **env) /* Option handling. */ while (1) { - opt = getopt_long (argc, argv, "be:c:d:nEhC", longopts, 0); + opt = getopt_long (argc, argv, "be:c:d:nf:mEhC", longopts, 0); if (opt == EOF) break; @@ -266,6 +272,12 @@ main (int argc, char **argv, char **env) case 'd': daemon_name = optarg; break; + case 'f': + inputfile = optarg; + break; + case 'm': + markfile = 1; + break; case 'n': no_error = 1; break; @@ -300,12 +312,28 @@ main (int argc, char **argv, char **env) vty_init_vtysh (); /* Read vtysh configuration file before connecting to daemons. */ - vtysh_read_config (config_default); + vtysh_read_config(config_default); + + if (markfile) + { + if (!inputfile) + { + fprintf(stderr, "-f option MUST be specified with -m option\n"); + return(1); + } + return(vtysh_mark_file(inputfile)); + } /* Start execution only if not in dry-run mode */ if(dryrun) - return(0); - + { + if (inputfile) + { + vtysh_read_config(inputfile); + } + return(0); + } + /* Ignore error messages */ if (no_error) freopen("/dev/null", "w", stdout); @@ -320,6 +348,12 @@ main (int argc, char **argv, char **env) exit(1); } + if (inputfile) + { + vtysh_read_config(inputfile); + exit(0); + } + /* If eval mode. */ if (cmd) { |