]> git.proxmox.com Git - mirror_frr.git/blobdiff - lib/vty.c
Revert "lib: Fix handling of poll"
[mirror_frr.git] / lib / vty.c
index bb3f14a50c7cabbffe776f8082b5cb2ae052c1e6..ae3e595364edae9b68ecd1f5ce52cfda46ac336e 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -57,7 +57,7 @@ static void vty_event (enum event, int, struct vty *);
 
 /* Extern host structure from command.c */
 extern struct host host;
-\f
+
 /* Vector which store each vty structure. */
 static vector vtyvec;
 
@@ -71,7 +71,7 @@ static char *vty_accesslist_name = NULL;
 static char *vty_ipv6_accesslist_name = NULL;
 
 /* VTY server thread. */
-vector Vvty_serv_thread;
+static vector Vvty_serv_thread;
 
 /* Current directory. */
 char *vty_cwd = NULL;
@@ -82,10 +82,14 @@ static int vty_config;
 /* Login password check. */
 static int no_password_check = 0;
 
+/* Restrict unauthenticated logins? */
+static const u_char restricted_mode_default = 0;
+static u_char restricted_mode = 0;
+
 /* Integrated configuration file path */
 char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
 
-\f
+
 /* VTY standard output function. */
 int
 vty_out (struct vty *vty, const char *format, ...)
@@ -149,17 +153,28 @@ vty_out (struct vty *vty, const char *format, ...)
 
 static int
 vty_log_out (struct vty *vty, const char *level, const char *proto_str,
-            const char *format, va_list va)
+            const char *format, struct timestamp_control *ctl, va_list va)
 {
   int ret;
   int len;
   char buf[1024];
 
+  if (!ctl->already_rendered)
+    {
+      ctl->len = quagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf));
+      ctl->already_rendered = 1;
+    }
+  if (ctl->len+1 >= sizeof(buf))
+    return -1;
+  memcpy(buf, ctl->buf, len = ctl->len);
+  buf[len++] = ' ';
+  buf[len] = '\0';
+
   if (level)
-    len = snprintf(buf, sizeof(buf), "%s: %s: ", level, proto_str);
+    ret = snprintf(buf+len, sizeof(buf)-len, "%s: %s: ", level, proto_str);
   else
-    len = snprintf(buf, sizeof(buf), "%s: ", proto_str);
-  if ((len < 0) || ((size_t)len >= sizeof(buf)))
+    ret = snprintf(buf+len, sizeof(buf)-len, "%s: ", proto_str);
+  if ((ret < 0) || ((size_t)(len += ret) >= sizeof(buf)))
     return -1;
 
   if (((ret = vsnprintf(buf+len, sizeof(buf)-len, format, va)) < 0) ||
@@ -176,10 +191,14 @@ vty_log_out (struct vty *vty, const char *level, const char *proto_str,
           drop the data and ignore. */
        return -1;
       /* Fatal I/O error. */
+      vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
       zlog_warn("%s: write failed to vty client fd %d, closing: %s",
                __func__, vty->fd, safe_strerror(errno));
       buffer_reset(vty->obuf);
-      vty_close(vty);
+      /* cannot call vty_close, because a parent routine may still try
+         to access the vty struct */
+      vty->status = VTY_CLOSE;
+      shutdown(vty->fd, SHUT_RDWR);
       return -1;
     }
   return 0;
@@ -189,19 +208,11 @@ vty_log_out (struct vty *vty, const char *level, const char *proto_str,
 void
 vty_time_print (struct vty *vty, int cr)
 {
-  time_t clock;
-  struct tm *tm;
-#define TIME_BUF 25
-  char buf [TIME_BUF];
-  int ret;
+  char buf [25];
   
-  time (&clock);
-  tm = localtime (&clock);
-
-  ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm);
-  if (ret == 0)
+  if (quagga_timestamp(0, buf, sizeof(buf)) == 0)
     {
-      zlog (NULL, LOG_INFO, "strftime error");
+      zlog (NULL, LOG_INFO, "quagga_timestamp error");
       return;
     }
   if (cr)
@@ -220,25 +231,26 @@ vty_hello (struct vty *vty)
     {
       FILE *f;
       char buf[4096];
-      int r;
+
       f = fopen (host.motdfile, "r");
       if (f)
        {
-         while (!feof (f))
+         while (fgets (buf, sizeof (buf), f))
            {
-             memset (buf, '\0', sizeof (buf));
-             r = fread (&buf, sizeof (buf) - 1, 1, f);
-             if (r < 0)
-               break;
-             vty_out (vty, buf);
+             char *s;
+             /* work backwards to ignore trailling isspace() */
+             for (s = buf + strlen (buf); (s > buf) && isspace ((int)*(s - 1));
+                  s--);
+             *s = '\0';
+             vty_out (vty, "%s%s", buf, VTY_NEWLINE);
            }
          fclose (f);
        }
       else
-       vty_out (vty, "MOTD file not found\n");
+       vty_out (vty, "MOTD file not found%s", VTY_NEWLINE);
     }
   else if (host.motd)
-    vty_out (vty, host.motd);
+    vty_out (vty, "%s", host.motd);
 }
 
 /* Put out prompt and wait input from user. */
@@ -310,6 +322,7 @@ vty_new ()
 
   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;
@@ -375,7 +388,7 @@ vty_auth (struct vty *vty, char *buf)
              /* AUTH_ENABLE_NODE */
              vty->fail = 0;
              vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
-             vty->node = VIEW_NODE;
+             vty->node = restricted_mode ? RESTRICTED_NODE : VIEW_NODE;
            }
        }
     }
@@ -387,6 +400,7 @@ vty_command (struct vty *vty, char *buf)
 {
   int ret;
   vector vline;
+  const char *protocolname;
 
   /* Split readline string up into the vector */
   vline = cmd_make_strvec (buf);
@@ -394,8 +408,33 @@ vty_command (struct vty *vty, char *buf)
   if (vline == NULL)
     return CMD_SUCCESS;
 
+#ifdef CONSUMED_TIME_CHECK
+  {
+    RUSAGE_T before;
+    RUSAGE_T after;
+    unsigned long realtime, cputime;
+
+    GETRUSAGE(&before);
+#endif /* CONSUMED_TIME_CHECK */
+
   ret = cmd_execute_command (vline, vty, NULL, 0);
 
+  /* Get the name of the protocol if any */
+  if (zlog_default)
+      protocolname = zlog_proto_names[zlog_default->protocol];
+  else
+      protocolname = zlog_proto_names[ZLOG_NONE];
+                                                                           
+#ifdef CONSUMED_TIME_CHECK
+    GETRUSAGE(&after);
+    if ((realtime = thread_consumed_time(&after, &before, &cputime)) >
+       CONSUMED_TIME_CHECK)
+      /* Warn about CPU hog that must be fixed. */
+      zlog_warn("SLOW COMMAND: command took %lums (cpu time %lums): %s",
+               realtime/1000, cputime/1000, buf);
+  }
+#endif /* CONSUMED_TIME_CHECK */
+
   if (ret != CMD_SUCCESS)
     switch (ret)
       {
@@ -407,7 +446,7 @@ vty_command (struct vty *vty, char *buf)
        vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
        break;
       case CMD_ERR_NO_MATCH:
-       vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE);
+       vty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE);
        break;
       case CMD_ERR_INCOMPLETE:
        vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
@@ -417,7 +456,7 @@ vty_command (struct vty *vty, char *buf)
 
   return ret;
 }
-\f
+
 static const char telnet_backward_char = 0x08;
 static const char telnet_space_char = ' ';
 
@@ -440,6 +479,7 @@ vty_ensure (struct vty *vty, int length)
     {
       vty->max *= 2;
       vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
+      vty->error_buf = XREALLOC (MTYPE_VTY, vty->error_buf, vty->max);
     }
 }
 
@@ -653,6 +693,7 @@ vty_end_config (struct vty *vty)
     {
     case VIEW_NODE:
     case ENABLE_NODE:
+    case RESTRICTED_NODE:
       /* Nothing to do. */
       break;
     case CONFIG_NODE:
@@ -665,6 +706,7 @@ vty_end_config (struct vty *vty)
     case BGP_IPV4_NODE:
     case BGP_IPV4M_NODE:
     case BGP_IPV6_NODE:
+    case BGP_IPV6M_NODE:
     case RMAP_NODE:
     case OSPF_NODE:
     case OSPF6_NODE:
@@ -692,9 +734,6 @@ vty_delete_char (struct vty *vty)
   int i;
   int size;
 
-  if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
-    return;
-
   if (vty->length == 0)
     {
       vty_down_level (vty);
@@ -709,6 +748,9 @@ vty_delete_char (struct vty *vty)
   vty->length--;
   memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
   vty->buf[vty->length] = '\0';
+  
+  if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+    return;
 
   vty_write (vty, &vty->buf[vty->cp], size - 1);
   vty_write (vty, &telnet_space_char, 1);
@@ -890,23 +932,23 @@ vty_complete_command (struct vty *vty)
 
 static void
 vty_describe_fold (struct vty *vty, int cmd_width,
-                  unsigned int desc_width, struct desc *desc)
+                  unsigned int desc_width, struct cmd_token *token)
 {
   char *buf;
   const char *cmd, *p;
   int pos;
 
-  cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
+  cmd = token->cmd[0] == '.' ? token->cmd + 1 : token->cmd;
 
   if (desc_width <= 0)
     {
-      vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
+      vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, token->desc, VTY_NEWLINE);
       return;
     }
 
-  buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
+  buf = XCALLOC (MTYPE_TMP, strlen (token->desc) + 1);
 
-  for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
+  for (p = token->desc; strlen (p) > desc_width; p += pos + 1)
     {
       for (pos = desc_width; pos > 0; pos--)
       if (*(p + pos) == ' ')
@@ -935,7 +977,7 @@ vty_describe_command (struct vty *vty)
   vector vline;
   vector describe;
   unsigned int i, width, desc_width;
-  struct desc *desc, *desc_cr = NULL;
+  struct cmd_token *token, *token_cr = NULL;
 
   vline = cmd_make_strvec (vty->buf);
 
@@ -957,33 +999,27 @@ vty_describe_command (struct vty *vty)
   switch (ret)
     {
     case CMD_ERR_AMBIGUOUS:
-      cmd_free_strvec (vline);
       vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
-      vty_prompt (vty);
-      vty_redraw_line (vty);
-      return;
+      goto out;
       break;
     case CMD_ERR_NO_MATCH:
-      cmd_free_strvec (vline);
       vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
-      vty_prompt (vty);
-      vty_redraw_line (vty);
-      return;
+      goto out;
       break;
     }  
 
   /* Get width of command string. */
   width = 0;
-  for (i = 0; i < vector_max (describe); i++)
-    if ((desc = vector_slot (describe, i)) != NULL)
+  for (i = 0; i < vector_active (describe); i++)
+    if ((token = vector_slot (describe, i)) != NULL)
       {
        unsigned int len;
 
-       if (desc->cmd[0] == '\0')
+       if (token->cmd[0] == '\0')
          continue;
 
-       len = strlen (desc->cmd);
-       if (desc->cmd[0] == '.')
+       len = strlen (token->cmd);
+       if (token->cmd[0] == '.')
          len--;
 
        if (width < len)
@@ -994,28 +1030,28 @@ vty_describe_command (struct vty *vty)
   desc_width = vty->width - (width + 6);
 
   /* Print out description. */
-  for (i = 0; i < vector_max (describe); i++)
-    if ((desc = vector_slot (describe, i)) != NULL)
+  for (i = 0; i < vector_active (describe); i++)
+    if ((token = vector_slot (describe, i)) != NULL)
       {
-       if (desc->cmd[0] == '\0')
+       if (token->cmd[0] == '\0')
          continue;
        
-       if (strcmp (desc->cmd, "<cr>") == 0)
+       if (strcmp (token->cmd, command_cr) == 0)
          {
-           desc_cr = desc;
+           token_cr = token;
            continue;
          }
 
-       if (!desc->str)
+       if (!token->desc)
          vty_out (vty, "  %-s%s",
-                  desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+                  token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
                   VTY_NEWLINE);
-       else if (desc_width >= strlen (desc->str))
+       else if (desc_width >= strlen (token->desc))
          vty_out (vty, "  %-*s  %s%s", width,
-                  desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
-                  desc->str, VTY_NEWLINE);
+                  token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
+                  token->desc, VTY_NEWLINE);
        else
-         vty_describe_fold (vty, width, desc_width, desc);
+         vty_describe_fold (vty, width, desc_width, token);
 
 #if 0
        vty_out (vty, "  %-*s %s%s", width
@@ -1024,22 +1060,24 @@ vty_describe_command (struct vty *vty)
 #endif /* 0 */
       }
 
-  if ((desc = desc_cr))
+  if ((token = token_cr))
     {
-      if (!desc->str)
+      if (!token->desc)
        vty_out (vty, "  %-s%s",
-                desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+                token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
                 VTY_NEWLINE);
-      else if (desc_width >= strlen (desc->str))
+      else if (desc_width >= strlen (token->desc))
        vty_out (vty, "  %-*s  %s%s", width,
-                desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
-                desc->str, VTY_NEWLINE);
+                token->cmd[0] == '.' ? token->cmd + 1 : token->cmd,
+                token->desc, VTY_NEWLINE);
       else
-       vty_describe_fold (vty, width, desc_width, desc);
+       vty_describe_fold (vty, width, desc_width, token);
     }
 
+out:
   cmd_free_strvec (vline);
-  vector_free (describe);
+  if (describe)
+    vector_free (describe);
 
   vty_prompt (vty);
   vty_redraw_line (vty);
@@ -1063,6 +1101,7 @@ vty_stop_input (struct vty *vty)
     {
     case VIEW_NODE:
     case ENABLE_NODE:
+    case RESTRICTED_NODE:
       /* Nothing to do. */
       break;
     case CONFIG_NODE:
@@ -1319,6 +1358,7 @@ vty_read (struct thread *thread)
              vty_event (VTY_READ, vty_sock, vty);
              return 0;
            }
+         vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
          zlog_warn("%s: read error on vty client fd %d, closing: %s",
                    __func__, vty->fd, safe_strerror(errno));
        }
@@ -1541,6 +1581,7 @@ vty_flush (struct thread *thread)
   switch (flushrc)
     {
     case BUFFER_ERROR:
+      vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
       zlog_warn("buffer_flush failed on vty client fd %d, closing",
                vty->fd);
       buffer_reset(vty->obuf);
@@ -1571,16 +1612,21 @@ vty_flush (struct thread *thread)
 static struct vty *
 vty_create (int vty_sock, union sockunion *su)
 {
+  char buf[SU_ADDRSTRLEN];
   struct vty *vty;
 
+  sockunion2str(su, buf, SU_ADDRSTRLEN);
+
   /* Allocate new vty structure and set up default values. */
   vty = vty_new ();
   vty->fd = vty_sock;
   vty->type = VTY_TERM;
-  vty->address = sockunion_su2str (su);
+  strcpy (vty->address, buf);
   if (no_password_check)
     {
-      if (host.advanced)
+      if (restricted_mode)
+        vty->node = RESTRICTED_NODE;
+      else if (host.advanced)
        vty->node = ENABLE_NODE;
       else
        vty->node = VIEW_NODE;
@@ -1644,13 +1690,13 @@ static int
 vty_accept (struct thread *thread)
 {
   int vty_sock;
-  struct vty *vty;
   union sockunion su;
   int ret;
   unsigned int on;
   int accept_sock;
   struct prefix *p = NULL;
   struct access_list *acl = NULL;
+  char buf[SU_ADDRSTRLEN];
 
   accept_sock = THREAD_FD (thread);
 
@@ -1676,10 +1722,8 @@ vty_accept (struct thread *thread)
       if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
          (access_list_apply (acl, p) == FILTER_DENY))
        {
-         char *buf;
          zlog (NULL, LOG_INFO, "Vty connection refused from %s",
-               (buf = sockunion_su2str (&su)));
-         free (buf);
+               sockunion2str (&su, buf, SU_ADDRSTRLEN));
          close (vty_sock);
          
          /* continue accepting connections */
@@ -1698,10 +1742,8 @@ vty_accept (struct thread *thread)
       if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
          (access_list_apply (acl, p) == FILTER_DENY))
        {
-         char *buf;
          zlog (NULL, LOG_INFO, "Vty connection refused from %s",
-               (buf = sockunion_su2str (&su)));
-         free (buf);
+               sockunion2str (&su, buf, SU_ADDRSTRLEN));
          close (vty_sock);
          
          /* continue accepting connections */
@@ -1723,7 +1765,10 @@ vty_accept (struct thread *thread)
     zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", 
          safe_strerror (errno));
 
-  vty = vty_create (vty_sock, &su);
+  zlog (NULL, LOG_INFO, "Vty connection from %s",
+       sockunion2str (&su, buf, SU_ADDRSTRLEN));
+
+  vty_create (vty_sock, &su);
 
   return 0;
 }
@@ -1769,6 +1814,7 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
       if (sock < 0)
        continue;
 
+      sockopt_v6only (ainfo->ai_family, sock);
       sockopt_reuseaddr (sock);
       sockopt_reuseport (sock);
 
@@ -1792,7 +1838,7 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
 
   freeaddrinfo (ainfo_save);
 }
-#endif /* HAVE_IPV6 && ! NRL */
+#else /* HAVE_IPV6 && ! NRL */
 
 /* Make vty server socket. */
 static void
@@ -1810,9 +1856,11 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family)
     {
       case AF_INET:
         naddr=&su.sin.sin_addr;
+        break;
 #ifdef HAVE_IPV6
       case AF_INET6:
         naddr=&su.sin6.sin6_addr;
+        break;
 #endif 
     }
 
@@ -1858,6 +1906,7 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family)
   /* Add vty server event. */
   vty_event (VTY_SERV, accept_sock, NULL);
 }
+#endif /* HAVE_IPV6 && ! NRL */
 
 #ifdef VTYSH
 /* For sockaddr_un. */
@@ -1891,11 +1940,11 @@ vty_serv_un (const char *path)
   memset (&serv, 0, sizeof (struct sockaddr_un));
   serv.sun_family = AF_UNIX;
   strncpy (serv.sun_path, path, strlen (path));
-#ifdef HAVE_SUN_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
   len = serv.sun_len = SUN_LEN(&serv);
 #else
   len = sizeof (serv.sun_family) + strlen (serv.sun_path);
-#endif /* HAVE_SUN_LEN */
+#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
 
   ret = bind (sock, (struct sockaddr *) &serv, len);
   if (ret < 0)
@@ -1988,6 +2037,7 @@ vtysh_flush(struct vty *vty)
       vty_event(VTYSH_WRITE, vty->fd, vty);
       break;
     case BUFFER_ERROR:
+      vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
       zlog_warn("%s: write error to fd %d, closing", __func__, vty->fd);
       buffer_reset(vty->obuf);
       vty_close(vty);
@@ -2023,6 +2073,7 @@ vtysh_read (struct thread *thread)
              vty_event (VTYSH_READ, sock, vty);
              return 0;
            }
+         vty->monitor = 0; /* disable monitoring to avoid infinite recursion */
          zlog_warn("%s: read failed on vtysh client fd %d, closing: %s",
                    __func__, sock, safe_strerror(errno));
        }
@@ -2106,7 +2157,10 @@ vty_serv_sock (const char *addr, unsigned short port, const char *path)
 #endif /* VTYSH */
 }
 
-/* Close vty interface. */
+/* Close vty interface.  Warning: call this only from functions that
+   will be careful not to access the vty afterwards (since it has
+   now been freed).  This is safest from top-level functions (called
+   directly by the thread dispatcher). */
 void
 vty_close (struct vty *vty)
 {
@@ -2138,11 +2192,12 @@ vty_close (struct vty *vty)
   if (vty->fd > 0)
     close (vty->fd);
 
-  if (vty->address)
-    XFREE (0, vty->address);
   if (vty->buf)
     XFREE (MTYPE_VTY, vty->buf);
 
+  if (vty->error_buf)
+    XFREE (MTYPE_VTY, vty->error_buf);
+
   /* Check configure. */
   vty_config_unlock (vty);
 
@@ -2177,30 +2232,37 @@ vty_read_file (FILE *confp)
 {
   int ret;
   struct vty *vty;
+  unsigned int line_num = 0;
 
   vty = vty_new ();
-  vty->fd = 0;                 /* stdout */
-  vty->type = VTY_TERM;
+  vty->fd = dup(STDERR_FILENO); /* vty_close() will close this */
+  if (vty->fd < 0)
+  {
+    /* Fine, we couldn't make a new fd. vty_close doesn't close stdout. */
+    vty->fd = STDOUT_FILENO;
+  }
+  vty->type = VTY_FILE;
   vty->node = CONFIG_NODE;
   
   /* Execute configuration file */
-  ret = config_from_file (vty, confp);
+  ret = config_from_file (vty, confp, &line_num);
+
+  /* Flush any previous errors before printing messages below */
+  buffer_flush_all (vty->obuf, vty->fd);
 
   if ( !((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO)) ) 
     {
       switch (ret)
        {
          case CMD_ERR_AMBIGUOUS:
-           fprintf (stderr, "Ambiguous command.\n");
+           fprintf (stderr, "*** Error reading config: Ambiguous command.\n");
            break;
          case CMD_ERR_NO_MATCH:
-           fprintf (stderr, "There is no such command.\n");
+           fprintf (stderr, "*** Error reading config: There is no such command.\n");
            break;
        }
-      fprintf (stderr, "Error occured during reading below line.\n%s\n", 
-              vty->buf);
-      vty_close (vty);
-      exit (1);
+      fprintf (stderr, "*** Error occured processing line %u, below:\n%s\n",
+                      line_num, vty->error_buf);
     }
 
   vty_close (vty);
@@ -2247,8 +2309,16 @@ vty_use_backup_config (char *fullpath)
     }
   
   while((c = read (sav, buffer, 512)) > 0)
-    write (tmp, buffer, c);
-  
+    {
+      if (write (tmp, buffer, c) <= 0)
+       {
+         free (fullpath_sav);
+         free (fullpath_tmp);
+         close (sav);
+         close (tmp);
+         return NULL;
+       }
+    }
   close (sav);
   close (tmp);
   
@@ -2278,16 +2348,22 @@ vty_read_config (char *config_file,
   char cwd[MAXPATHLEN];
   FILE *confp = NULL;
   char *fullpath;
+  char *tmp = NULL;
 
   /* If -f flag specified. */
   if (config_file != NULL)
     {
       if (! IS_DIRECTORY_SEP (config_file[0]))
         {
-          getcwd (cwd, MAXPATHLEN);
-          fullpath = XMALLOC (MTYPE_TMP, 
+          if (getcwd (cwd, MAXPATHLEN) == NULL)
+           {
+             fprintf (stderr, "Failure to determine Current Working Directory %d!\n", errno);
+             exit (1);
+           }
+          tmp = XMALLOC (MTYPE_TMP, 
                              strlen (cwd) + strlen (config_file) + 2);
-          sprintf (fullpath, "%s/%s", cwd, config_file);
+          sprintf (tmp, "%s/%s", cwd, config_file);
+          fullpath = tmp;
         }
       else
         fullpath = config_file;
@@ -2296,19 +2372,25 @@ vty_read_config (char *config_file,
 
       if (confp == NULL)
         {
+          fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
+                   __func__, fullpath, safe_strerror (errno));
+          
           confp = vty_use_backup_config (fullpath);
           if (confp)
             fprintf (stderr, "WARNING: using backup configuration file!\n");
           else
             {
               fprintf (stderr, "can't open configuration file [%s]\n", 
-                   config_file);
+                      config_file);
               exit(1);
             }
         }
     }
   else
     {
+
+      host_config_set (config_default_dir);
+
 #ifdef VTYSH
       int ret;
       struct stat conf_stat;
@@ -2331,13 +2413,15 @@ vty_read_config (char *config_file,
         {
           ret = stat (integrate_default, &conf_stat);
           if (ret >= 0)
-            return;
+           goto tmp_free_and_out;
         }
 #endif /* VTYSH */
-
       confp = fopen (config_default_dir, "r");
       if (confp == NULL)
         {
+          fprintf (stderr, "%s: failed to open configuration file %s: %s\n",
+                   __func__, config_default_dir, safe_strerror (errno));
+          
           confp = vty_use_backup_config (config_default_dir);
           if (confp)
             {
@@ -2347,9 +2431,9 @@ vty_read_config (char *config_file,
           else
             {
               fprintf (stderr, "can't open configuration file [%s]\n",
-                                config_default_dir);
-                 exit (1);
-               }
+                      config_default_dir);
+             goto tmp_free_and_out;
+            }
         }      
       else
         fullpath = config_default_dir;
@@ -2360,46 +2444,62 @@ vty_read_config (char *config_file,
   fclose (confp);
 
   host_config_set (fullpath);
+
+tmp_free_and_out:
+  if (tmp)
+    XFREE (MTYPE_TMP, fullpath);
 }
 
 /* Small utility function which output log to the VTY. */
 void
 vty_log (const char *level, const char *proto_str,
-        const char *format, va_list va)
+        const char *format, struct timestamp_control *ctl, va_list va)
 {
   unsigned int i;
   struct vty *vty;
+  
+  if (!vtyvec)
+    return;
 
-  for (i = 0; i < vector_max (vtyvec); i++)
+  for (i = 0; i < vector_active (vtyvec); i++)
     if ((vty = vector_slot (vtyvec, i)) != NULL)
       if (vty->monitor)
        {
          va_list ac;
          va_copy(ac, va);
-         vty_log_out (vty, level, proto_str, format, ac);
+         vty_log_out (vty, level, proto_str, format, ctl, ac);
          va_end(ac);
        }
 }
 
 /* Async-signal-safe version of vty_log for fixed strings. */
 void
-vty_log_fixed (const char *buf, size_t len)
+vty_log_fixed (char *buf, size_t len)
 {
   unsigned int i;
   struct iovec iov[2];
+  char crlf[4] = "\r\n";
 
-  iov[0].iov_base = buf;
+  /* vty may not have been initialised */
+  if (!vtyvec)
+    return;
+  
+  iov[0].iov_base = (void *)buf;
   iov[0].iov_len = len;
-  iov[1].iov_base = "\r\n";
+  iov[1].iov_base = crlf;
   iov[1].iov_len = 2;
 
-  for (i = 0; i < vector_max (vtyvec); i++)
+  for (i = 0; i < vector_active (vtyvec); i++)
     {
       struct vty *vty;
       if (((vty = vector_slot (vtyvec, i)) != NULL) && vty->monitor)
        /* N.B. We don't care about the return code, since process is
           most likely just about to die anyway. */
-       writev(vty->fd, iov, 2);
+       if (writev(vty->fd, iov, 2) == -1)
+         {
+           fprintf(stderr, "Failure to writev: %d\n", errno);
+           exit(-1);
+         }
     }
 }
 
@@ -2424,9 +2524,9 @@ vty_config_unlock (struct vty *vty)
     }
   return vty->config;
 }
-\f
+
 /* Master of the threads. */
-static struct thread_master *master;
+static struct thread_master *vty_master;
 
 static void
 vty_event (enum event event, int sock, struct vty *vty)
@@ -2436,22 +2536,23 @@ vty_event (enum event event, int sock, struct vty *vty)
   switch (event)
     {
     case VTY_SERV:
-      vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
+      vty_serv_thread = thread_add_read (vty_master, vty_accept, vty, sock);
       vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
       break;
 #ifdef VTYSH
     case VTYSH_SERV:
-      thread_add_read (master, vtysh_accept, vty, sock);
+      vty_serv_thread = thread_add_read (vty_master, vtysh_accept, vty, sock);
+      vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
       break;
     case VTYSH_READ:
-      vty->t_read = thread_add_read (master, vtysh_read, vty, sock);
+      vty->t_read = thread_add_read (vty_master, vtysh_read, vty, sock);
       break;
     case VTYSH_WRITE:
-      vty->t_write = thread_add_write (master, vtysh_write, vty, sock);
+      vty->t_write = thread_add_write (vty_master, vtysh_write, vty, sock);
       break;
 #endif /* VTYSH */
     case VTY_READ:
-      vty->t_read = thread_add_read (master, vty_read, vty, sock);
+      vty->t_read = thread_add_read (vty_master, vty_read, vty, sock);
 
       /* Time out treatment. */
       if (vty->v_timeout)
@@ -2459,12 +2560,12 @@ vty_event (enum event event, int sock, struct vty *vty)
          if (vty->t_timeout)
            thread_cancel (vty->t_timeout);
          vty->t_timeout = 
-           thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
+           thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
        }
       break;
     case VTY_WRITE:
       if (! vty->t_write)
-       vty->t_write = thread_add_write (master, vty_flush, vty, sock);
+       vty->t_write = thread_add_write (vty_master, vty_flush, vty, sock);
       break;
     case VTY_TIMEOUT_RESET:
       if (vty->t_timeout)
@@ -2475,12 +2576,12 @@ vty_event (enum event event, int sock, struct vty *vty)
       if (vty->v_timeout)
        {
          vty->t_timeout = 
-           thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
+           thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
        }
       break;
     }
 }
-\f
+
 DEFUN (config_who,
        config_who_cmd,
        "who",
@@ -2489,7 +2590,7 @@ DEFUN (config_who,
   unsigned int i;
   struct vty *v;
 
-  for (i = 0; i < vector_max (vtyvec); i++)
+  for (i = 0; i < vector_active (vtyvec); i++)
     if ((v = vector_slot (vtyvec, i)) != NULL)
       vty_out (vty, "%svty[%d] connected from %s.%s",
               v->config ? "*" : " ",
@@ -2659,6 +2760,26 @@ DEFUN (no_vty_login,
   return CMD_SUCCESS;
 }
 
+/* initial mode. */
+DEFUN (vty_restricted_mode,
+       vty_restricted_mode_cmd,
+       "anonymous restricted",
+       "Restrict view commands available in anonymous, unauthenticated vty\n")
+{
+  restricted_mode = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (vty_no_restricted_mode,
+       vty_no_restricted_mode_cmd,
+       "no anonymous restricted",
+       NO_STR
+       "Enable password checking\n")
+{
+  restricted_mode = 0;
+  return CMD_SUCCESS;
+}
+
 DEFUN (service_advanced_vty,
        service_advanced_vty_cmd,
        "service advanced-vty",
@@ -2701,6 +2822,13 @@ DEFUN (terminal_no_monitor,
   return CMD_SUCCESS;
 }
 
+ALIAS (terminal_no_monitor,
+       no_terminal_monitor_cmd,
+       "no terminal monitor",
+       NO_STR
+       "Set terminal line parameters\n"
+       "Copy debug output to the current terminal line\n")
+
 DEFUN (show_history,
        show_history_cmd,
        "show history",
@@ -2749,7 +2877,15 @@ vty_config_write (struct vty *vty)
   /* login */
   if (no_password_check)
     vty_out (vty, " no login%s", VTY_NEWLINE);
-
+    
+  if (restricted_mode != restricted_mode_default)
+    {
+      if (restricted_mode_default)
+        vty_out (vty, " no anonymous restricted%s", VTY_NEWLINE);
+      else
+        vty_out (vty, " anonymous restricted%s", VTY_NEWLINE);
+    }
+  
   vty_out (vty, "!%s", VTY_NEWLINE);
 
   return CMD_SUCCESS;
@@ -2770,7 +2906,7 @@ vty_reset ()
   struct vty *vty;
   struct thread *vty_serv_thread;
 
-  for (i = 0; i < vector_max (vtyvec); i++)
+  for (i = 0; i < vector_active (vtyvec); i++)
     if ((vty = vector_slot (vtyvec, i)) != NULL)
       {
        buffer_reset (vty->obuf);
@@ -2778,7 +2914,7 @@ vty_reset ()
        vty_close (vty);
       }
 
-  for (i = 0; i < vector_max (Vvty_serv_thread); i++)
+  for (i = 0; i < vector_active (Vvty_serv_thread); i++)
     if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
       {
        thread_cancel (vty_serv_thread);
@@ -2811,8 +2947,21 @@ vty_save_cwd (void)
 
   if (!c)
     {
-      chdir (SYSCONFDIR);
-      getcwd (cwd, MAXPATHLEN);
+      /*
+       * At this point if these go wrong, more than likely
+       * the whole world is coming down around us
+       * Hence not worrying about it too much.
+       */
+      if (!chdir (SYSCONFDIR))
+       {
+         fprintf(stderr, "Failure to chdir to %s, errno: %d\n", SYSCONFDIR, errno);
+         exit(-1);
+       }
+      if (getcwd (cwd, MAXPATHLEN) == NULL)
+       {
+         fprintf(stderr, "Failure to getcwd, errno: %d\n", errno);
+         exit(-1);
+       }
     }
 
   vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
@@ -2852,7 +3001,7 @@ vty_init (struct thread_master *master_thread)
 
   vtyvec = vector_init (VECTOR_MIN_SIZE);
 
-  master = master_thread;
+  vty_master = master_thread;
 
   /* Initilize server thread vector. */
   Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
@@ -2860,6 +3009,8 @@ vty_init (struct thread_master *master_thread)
   /* Install bgp top node. */
   install_node (&vty_node, vty_config_write);
 
+  install_element (RESTRICTED_NODE, &config_who_cmd);
+  install_element (RESTRICTED_NODE, &show_history_cmd);
   install_element (VIEW_NODE, &config_who_cmd);
   install_element (VIEW_NODE, &show_history_cmd);
   install_element (ENABLE_NODE, &config_who_cmd);
@@ -2869,6 +3020,7 @@ vty_init (struct thread_master *master_thread)
   install_element (CONFIG_NODE, &show_history_cmd);
   install_element (ENABLE_NODE, &terminal_monitor_cmd);
   install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
+  install_element (ENABLE_NODE, &no_terminal_monitor_cmd);
   install_element (ENABLE_NODE, &show_history_cmd);
 
   install_default (VTY_NODE);
@@ -2879,8 +3031,24 @@ vty_init (struct thread_master *master_thread)
   install_element (VTY_NODE, &no_vty_access_class_cmd);
   install_element (VTY_NODE, &vty_login_cmd);
   install_element (VTY_NODE, &no_vty_login_cmd);
+  install_element (VTY_NODE, &vty_restricted_mode_cmd);
+  install_element (VTY_NODE, &vty_no_restricted_mode_cmd);
 #ifdef HAVE_IPV6
   install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
   install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
 #endif /* HAVE_IPV6 */
 }
+
+void
+vty_terminate (void)
+{
+  if (vty_cwd)
+    XFREE (MTYPE_TMP, vty_cwd);
+
+  if (vtyvec && Vvty_serv_thread)
+    {
+      vty_reset ();
+      vector_free (vtyvec);
+      vector_free (Vvty_serv_thread);
+    }
+}