[vtysh] Never skip authentication, and add support for multiple -c commands

2006-07-27 Andrew J. Schorr <ajschorr@alumni.princeton.edu>

	* vtysh.1: Document new options -d and -E, and note that now multiple
	  -c options may be supplied, with embedded linefeed now supported.
	  In BUGS section, remove warning about vtysh causing a daemon
	  to freeze, since this has been fixed.
	* vtysh_main.c: (usage) Add new -d and -E options.  And note that
	  -c can be used multiple times, possibly with embedded linefeeds.
	  (longopts) Add new -d and -E options.
	  (main) Add new -d and -E options, and create a linked list to
	  support multiple -c options.  Do not call vtysh_connect_all until
	  after vtysh_read_config(config_default) and vtysh_auth have
	  succeeded.  This prevents the vtysh.conf file from configuring
	  any daemons, and it ensures that authentication has been passed
	  before we send any commands to any daemons.  Call vtysh_connect_all
	  with any daemon name supplied with -d.  If it is unable to connect
	  to any daemons, issue an error message and exit immediately.
	  When used in -c mode, call vtysh_execute("enable") before
	  executing the commands in order to match interactive behavior.
	  And detect embedded linefeed chars in -c commands and break them up
	  appropriately.
	* vtysh.h: (vtysh_connect_all) Fix proto to reflect new
	  daemon_name argument, and that it now returns an integer -- the
	  number of daemons to which we were able to connect.
	* vtysh.c: (vtysh_connect_all) Add a new daemon_name argument.
	  If supplied, connect only to that daemon.  And return
	  the number of daemons to which we were able to connect.
	  (vtysh_prompt): Performance enhancement -- make struct utsname
	  static so we call uname to get the hostname only once.
diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
index 7f8e059..134bcf7 100644
--- a/vtysh/vtysh_main.c
+++ b/vtysh/vtysh_main.c
@@ -32,6 +32,7 @@
 #include <lib/version.h>
 #include "getopt.h"
 #include "command.h"
+#include "memory.h"
 
 #include "vtysh/vtysh.h"
 #include "vtysh/vtysh_user.h"
@@ -132,10 +133,15 @@
     fprintf (stderr, "Try `%s --help' for more information.\n", progname);
   else
     printf ("Usage : %s [OPTION...]\n\n" \
-	    "Integrated shell for Quagga routing software suite. \n\n"\
+	    "Integrated shell for Quagga routing software suite. \n\n" \
 	    "-b, --boot               Execute boot startup configuration\n" \
-	    "-c, --command            Execute argument as command\n "\
+	    "-c, --command            Execute argument as command\n" \
+	    "-d, --daemon             Connect only to the specified daemon\n" \
+	    "-E, --echo               Echo prompt and command in -c mode\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" \
+	    "characters in one or more of the commands.\n\n" \
 	    "Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
 
   exit (status);
@@ -148,6 +154,8 @@
   /* For compatibility with older zebra/quagga versions */
   { "eval",                 required_argument,       NULL, 'e'},
   { "command",              required_argument,       NULL, 'c'},
+  { "daemon",               required_argument,       NULL, 'd'},
+  { "echo",                 no_argument,             NULL, 'E'},
   { "help",                 no_argument,             NULL, 'h'},
   { 0 }
 };
@@ -187,9 +195,14 @@
 {
   char *p;
   int opt;
-  int eval_flag = 0;
   int boot_flag = 0;
-  char *eval_line = NULL;
+  const char *daemon_name = NULL;
+  struct cmd_rec {
+    const char *line;
+    struct cmd_rec *next;
+  } *cmd = NULL;
+  struct cmd_rec *tail = NULL;
+  int echo_command = 0;
 
   /* Preserve name of myself. */
   progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
@@ -197,7 +210,7 @@
   /* Option handling. */
   while (1) 
     {
-      opt = getopt_long (argc, argv, "be:c:h", longopts, 0);
+      opt = getopt_long (argc, argv, "be:c:d:Eh", longopts, 0);
     
       if (opt == EOF)
 	break;
@@ -211,8 +224,23 @@
 	  break;
 	case 'e':
 	case 'c':
-	  eval_flag = 1;
-	  eval_line = optarg;
+	  {
+	    struct cmd_rec *cr;
+	    cr = XMALLOC(0, sizeof(*cr));
+	    cr->line = optarg;
+	    cr->next = NULL;
+	    if (tail)
+	      tail->next = cr;
+	    else
+	      cmd = cr;
+	    tail = cr;
+	  }
+	  break;
+	case 'd':
+	  daemon_name = optarg;
+	  break;
+	case 'E':
+	  echo_command = 1;
 	  break;
 	case 'h':
 	  usage (0);
@@ -239,15 +267,48 @@
 
   sort_node ();
 
-  vtysh_connect_all ();
-
-  /* Read vtysh configuration file. */
+  /* Read vtysh configuration file before connecting to daemons. */
   vtysh_read_config (config_default);
 
-  /* If eval mode. */
-  if (eval_flag)
+  /* Make sure we pass authentication before proceeding. */
+  vtysh_auth ();
+
+  /* Do not connect until we have passed authentication. */
+  if (vtysh_connect_all (daemon_name) <= 0)
     {
-      vtysh_execute_no_pager (eval_line);
+      fprintf(stderr, "Exiting: failed to connect to any daemons.\n");
+      exit(1);
+    }
+
+  /* If eval mode. */
+  if (cmd)
+    {
+      /* Enter into enable node. */
+      vtysh_execute ("enable");
+
+      while (cmd != NULL)
+        {
+	  char *eol;
+
+	  while ((eol = strchr(cmd->line, '\n')) != NULL)
+	    {
+	      *eol = '\0';
+	      if (echo_command)
+	        printf("%s%s\n", vtysh_prompt(), cmd->line);
+	      vtysh_execute_no_pager(cmd->line);
+	      cmd->line = eol+1;
+	    }
+	  if (echo_command)
+	    printf("%s%s\n", vtysh_prompt(), cmd->line);
+	  vtysh_execute_no_pager (cmd->line);
+
+	  {
+	    struct cmd_rec *cr;
+	    cr = cmd;
+	    cmd = cmd->next;
+	    XFREE(0, cr);
+	  }
+        }
       exit (0);
     }
   
@@ -270,8 +331,6 @@
 
   vty_hello (vty);
 
-  vtysh_auth ();
-
   /* Enter into enable node. */
   vtysh_execute ("enable");