From: Dinesh Dutt <[email protected]>

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.

Signed-off-by: Dinesh Dutt <[email protected]>
---
 lib/command.c        |   2 +-
 lib/command.h        |   2 +-
 vtysh/vtysh.c        | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 vtysh/vtysh.h        |   4 +-
 vtysh/vtysh_config.c |   2 +-
 vtysh/vtysh_main.c   |  42 ++++++++++++--
 6 files changed, 197 insertions(+), 10 deletions(-)

diff --git a/lib/command.c b/lib/command.c
index 37767e9..19d6fd1 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -4046,7 +4046,7 @@ DEFUN (no_banner_motd,
 
 /* Set config filename.  Called from vty.c */
 void
-host_config_set (char *filename)
+host_config_set (const char *filename)
 {
   if (host.config)
     XFREE (MTYPE_HOST, host.config);
diff --git a/lib/command.h b/lib/command.h
index f98a609..7d6cf5b 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -543,7 +543,7 @@ extern struct cmd_element config_quit_cmd;
 extern struct cmd_element config_help_cmd;
 extern struct cmd_element config_list_cmd;
 extern char *host_config_file (void);
-extern void host_config_set (char *);
+extern void host_config_set (const char *);
 
 extern void print_version (const char *);
 
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 00ce62c..c9e5fbb 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -446,6 +446,157 @@ vtysh_execute (const char *line)
   return vtysh_execute_func (line, 1);
 }
 
+int
+vtysh_mark_file (const 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)
@@ -464,13 +615,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 1681a71..9f8fb23 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -53,7 +53,9 @@ void vtysh_config_write (void);
 
 int vtysh_config_from_file (struct vty *, FILE *);
 
-int vtysh_read_config (char *);
+int vtysh_mark_file(const char *filename);
+
+int vtysh_read_config (const char *);
 
 void vtysh_config_parse (char *);
 
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index 94dc995..b5869dd 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -388,7 +388,7 @@ vtysh_read_file (FILE *confp)
 
 /* Read up configuration file from config_default_dir. */
 int
-vtysh_read_config (char *config_default_dir)
+vtysh_read_config (const char *config_default_dir)
 {
   FILE *confp = NULL;
 
diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
index aa7d021..8caf7a6 100644
--- a/vtysh/vtysh_main.c
+++ b/vtysh/vtysh_main.c
@@ -135,8 +135,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" \
@@ -154,10 +156,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 }
 };
 
@@ -216,6 +220,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;
@@ -223,6 +228,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]);
@@ -234,7 +240,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;
@@ -263,6 +269,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;
@@ -297,12 +309,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);
@@ -317,6 +345,12 @@ main (int argc, char **argv, char **env)
       exit(1);
     }
 
+  if (inputfile)
+    {
+      vtysh_read_config(inputfile);
+      exit(0);
+    }
+
   /* If eval mode. */
   if (cmd)
     {
-- 
1.9.1


_______________________________________________
Quagga-dev mailing list
[email protected]
https://lists.quagga.net/mailman/listinfo/quagga-dev

Reply via email to