* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with GNU Zebra; see the file COPYING. If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "vty.h"
#include "privs.h"
#include "network.h"
+#include "libfrr.h"
#include <arpa/telnet.h>
#include <termios.h>
static int do_log_commands = 0;
-/* VTY standard output function. */
-int
-vty_out (struct vty *vty, const char *format, ...)
+static int
+vty_out_variadic (struct vty *vty, const char *format, va_list args)
{
- va_list args;
int len = 0;
int size = 1024;
char buf[1024];
char *p = NULL;
+ va_list cp;
if (vty_shell (vty))
- {
- va_start (args, format);
- vprintf (format, args);
- va_end (args);
- }
+ vprintf (format, args);
else
{
/* Try to write to initial buffer. */
- va_start (args, format);
- len = vsnprintf (buf, sizeof(buf), format, args);
- va_end (args);
+ va_copy (cp, args);
+ len = vsnprintf (buf, sizeof(buf), format, cp);
+ va_end (cp);
/* Initial buffer is not enough. */
if (len < 0 || len >= size)
if (! p)
return -1;
- va_start (args, format);
- len = vsnprintf (p, size, format, args);
- va_end (args);
+ va_copy (cp, args);
+ len = vsnprintf (p, size, format, cp);
+ va_end (cp);
if (len > -1 && len < size)
break;
return len;
}
+/* VTY standard output function. */
+int
+vty_out (struct vty *vty, const char *format, ...)
+{
+ int len;
+ va_list args;
+
+ va_start (args, format);
+ len = vty_out_variadic (vty, format, args);
+ va_end (args);
+
+ return len;
+}
+
+int
+vty_outln (struct vty *vty, const char *format, ...)
+{
+ int len;
+ va_list args;
+
+ va_start (args, format);
+ len = vty_out_variadic (vty, format, args);
+ va_end (args);
+
+ return len + vty_out (vty, "%s", VTYNL);
+}
static int
vty_log_out (struct vty *vty, const char *level, const char *proto_str,
for (s = buf + strlen (buf); (s > buf) && isspace ((int)*(s - 1));
s--);
*s = '\0';
- vty_out (vty, "%s%s", buf, VTY_NEWLINE);
+ vty_outln (vty, "%s", buf);
}
fclose (f);
}
else
- vty_out (vty, "MOTD file not found%s", VTY_NEWLINE);
+ vty_outln (vty, "MOTD file not found");
}
else if (host.motd)
vty_out (vty, "%s", host.motd);
{
if (vty->node == AUTH_NODE)
{
- vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
+ vty_outln (vty, "%% Bad passwords, too many failures!");
vty->status = VTY_CLOSE;
}
else
{
/* AUTH_ENABLE_NODE */
vty->fail = 0;
- vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
+ vty_outln (vty, "%% Bad enable passwords, too many failures!");
vty->status = VTY_CLOSE;
}
}
ret = cmd_execute_command (vline, vty, NULL, 0);
/* Get the name of the protocol if any */
- protocolname = zlog_protoname();
+ protocolname = frr_protoname;
#ifdef CONSUMED_TIME_CHECK
GETRUSAGE(&after);
{
case CMD_WARNING:
if (vty->type == VTY_FILE)
- vty_out (vty, "Warning...%s", VTY_NEWLINE);
+ vty_outln (vty, "Warning...");
break;
case CMD_ERR_AMBIGUOUS:
- vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+ vty_outln (vty, "%% Ambiguous command.");
break;
case CMD_ERR_NO_MATCH:
- vty_out (vty, "%% [%s] Unknown command: %s%s", protocolname, buf, VTY_NEWLINE);
+ vty_outln (vty, "%% [%s] Unknown command: %s", protocolname, buf);
break;
case CMD_ERR_INCOMPLETE:
- vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
+ vty_outln (vty, "%% Command incomplete.");
break;
}
cmd_free_strvec (vline);
static void
vty_down_level (struct vty *vty)
{
- vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, VTYNL);
cmd_exit (vty);
vty_prompt (vty);
vty->cp = 0;
static void
vty_end_config (struct vty *vty)
{
- vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, VTYNL);
switch (vty->node)
{
case ZEBRA_NODE:
case RIP_NODE:
case RIPNG_NODE:
+ case EIGRP_NODE:
case BGP_NODE:
case BGP_VPNV4_NODE:
case BGP_VPNV6_NODE:
- case BGP_ENCAP_NODE:
- case BGP_ENCAPV6_NODE:
case BGP_VRF_POLICY_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
cmd_free_strvec (vline);
- vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, VTYNL);
switch (ret)
{
case CMD_ERR_AMBIGUOUS:
- vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+ vty_outln (vty, "%% Ambiguous command.");
vty_prompt (vty);
vty_redraw_line (vty);
break;
case CMD_ERR_NO_MATCH:
- /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
+ /* vty_out (vty, "%% There is no matched command.%s", VTYNL); */
vty_prompt (vty);
vty_redraw_line (vty);
break;
if (!matched[0])
{
/* 2016-11-28 equinox -- need to debug, SEGV here */
- vty_out (vty, "%% CLI BUG: FULL_MATCH with NULL str%s", VTY_NEWLINE);
+ vty_outln (vty, "%% CLI BUG: FULL_MATCH with NULL str");
vty_prompt (vty);
vty_redraw_line (vty);
break;
vty_backward_pure_word (vty);
vty_insert_word_overwrite (vty, matched[0]);
vty_self_insert (vty, ' ');
- XFREE (MTYPE_TMP, matched[0]);
+ XFREE (MTYPE_COMPLETION, matched[0]);
break;
case CMD_COMPLETE_MATCH:
vty_prompt (vty);
vty_redraw_line (vty);
vty_backward_pure_word (vty);
vty_insert_word_overwrite (vty, matched[0]);
- XFREE (MTYPE_TMP, matched[0]);
+ XFREE (MTYPE_COMPLETION, matched[0]);
break;
case CMD_COMPLETE_LIST_MATCH:
for (i = 0; matched[i] != NULL; i++)
{
if (i != 0 && ((i % 6) == 0))
- vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, VTYNL);
vty_out (vty, "%-10s ", matched[i]);
- XFREE (MTYPE_TMP, matched[i]);
+ XFREE (MTYPE_COMPLETION, matched[i]);
}
- vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, VTYNL);
vty_prompt (vty);
vty_redraw_line (vty);
if (desc_width <= 0)
{
- vty_out (vty, " %-*s %s%s", cmd_width, cmd, token->desc, VTY_NEWLINE);
+ vty_outln (vty, " %-*s %s", cmd_width, cmd, token->desc);
return;
}
strncpy (buf, p, pos);
buf[pos] = '\0';
- vty_out (vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
+ vty_outln (vty, " %-*s %s", cmd_width, cmd, buf);
cmd = "";
}
- vty_out (vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
+ vty_outln (vty, " %-*s %s", cmd_width, cmd, p);
XFREE (MTYPE_TMP, buf);
}
describe = cmd_describe_command (vline, vty, &ret);
- vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, VTYNL);
/* Ambiguous error. */
switch (ret)
{
case CMD_ERR_AMBIGUOUS:
- vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+ vty_outln (vty, "%% Ambiguous command.");
goto out;
break;
case CMD_ERR_NO_MATCH:
- vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
+ vty_outln (vty, "%% There is no matched command.");
goto out;
break;
}
}
if (!token->desc)
- vty_out (vty, " %-s%s",
- token->text,
- VTY_NEWLINE);
+ vty_outln (vty, " %-s",
+ token->text);
else if (desc_width >= strlen (token->desc))
- vty_out (vty, " %-*s %s%s", width,
+ vty_outln (vty, " %-*s %s", width,
token->text,
- token->desc, VTY_NEWLINE);
+ token->desc);
else
vty_describe_fold (vty, width, desc_width, token);
+ if (IS_VARYING_TOKEN(token->type))
+ {
+ const char *ref = vector_slot(vline, vector_active(vline) - 1);
+
+ vector varcomps = vector_init (VECTOR_MIN_SIZE);
+ cmd_variable_complete (token, ref, varcomps);
+
+ if (vector_active(varcomps) > 0)
+ {
+ vty_out(vty, " ");
+ for (size_t j = 0; j < vector_active (varcomps); j++)
+ {
+ char *item = vector_slot (varcomps, j);
+ vty_out(vty, " %s", item);
+ XFREE(MTYPE_COMPLETION, item);
+ }
+ vty_out (vty, VTYNL);
+ }
+ vector_free(varcomps);
+ }
#if 0
vty_out (vty, " %-*s %s%s", width
desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
- desc->str ? desc->str : "", VTY_NEWLINE);
+ desc->str ? desc->str : "", VTYNL);
#endif /* 0 */
}
if ((token = token_cr))
{
if (!token->desc)
- vty_out (vty, " %-s%s",
- token->text,
- VTY_NEWLINE);
+ vty_outln (vty, " %-s",
+ token->text);
else if (desc_width >= strlen (token->desc))
- vty_out (vty, " %-*s %s%s", width,
+ vty_outln (vty, " %-*s %s", width,
token->text,
- token->desc, VTY_NEWLINE);
+ token->desc);
else
vty_describe_fold (vty, width, desc_width, token);
}
{
vty->cp = vty->length = 0;
vty_clear_buf (vty);
- vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, VTYNL);
switch (vty->node)
{
case ZEBRA_NODE:
case RIP_NODE:
case RIPNG_NODE:
+ case EIGRP_NODE:
case BGP_NODE:
case RMAP_NODE:
case OSPF_NODE:
vty_out (vty, "SE ");
break;
case TELOPT_ECHO:
- vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
+ vty_outln (vty, "TELOPT_ECHO ");
break;
case TELOPT_SGA:
- vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
+ vty_outln (vty, "TELOPT_SGA ");
break;
case TELOPT_NAWS:
- vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
+ vty_outln (vty, "TELOPT_NAWS ");
break;
default:
vty_out (vty, "%x ", buf[i]);
break;
}
}
- vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, VTYNL);
#endif /* TELNET_OPTION_DEBUG */
vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
#ifdef TELNET_OPTION_DEBUG
- vty_out(vty, "TELNET NAWS window size negotiation completed: "
- "width %d, height %d%s",
- vty->width, vty->height, VTY_NEWLINE);
+ vty_outln (vty, "TELNET NAWS window size negotiation completed: "
+ "width %d, height %d",
+ vty->width, vty->height);
#endif
}
break;
break;
case '\n':
case '\r':
- vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, VTYNL);
vty_execute (vty);
break;
case '\t':
/* Vty is not available if password isn't set. */
if (host.password == NULL && host.password_encrypt == NULL)
{
- vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
+ vty_outln (vty, "Vty password is not set.");
vty->status = VTY_CLOSE;
vty_close (vty);
return NULL;
/* Say hello to the world. */
vty_hello (vty);
if (! no_password_check)
- vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+ vty_outln (vty, "%sUser Access Verification%s", VTYNL,
+ VTYNL);
/* Setting up terminal. */
vty_will_echo (vty);
/* Clear command line buffer. */
vty->cp = vty->length = 0;
vty_clear_buf (vty);
- vty_out (vty, "%% Command is too long.%s", VTY_NEWLINE);
+ vty_outln (vty, "%% Command is too long.");
}
else
{
if (ret == CMD_SUSPEND)
break;
- /* warning: watchquagga hardcodes this result write */
+ /* warning: watchfrr hardcodes this result write */
header[3] = ret;
buffer_put(vty->obuf, header, 4);
}
}
- vty_event (VTYSH_READ, sock, vty);
+ if (vty->status == VTY_CLOSE)
+ vty_close (vty);
+ else
+ vty_event (VTYSH_READ, sock, vty);
return 0;
}
/* Clear buffer*/
buffer_reset (vty->obuf);
- vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
+ vty_outln (vty, "%sVty connection is timed out.", VTYNL);
/* Close connection. */
vty->status = VTY_CLOSE;
static void
vty_event (enum event event, int sock, struct vty *vty)
{
- struct thread *vty_serv_thread;
+ struct thread *vty_serv_thread = NULL;
switch (event)
{
case VTY_SERV:
- vty_serv_thread = thread_add_read (vty_master, vty_accept, vty, sock);
+ vty_serv_thread = thread_add_read(vty_master, vty_accept, vty, sock, NULL);
vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
break;
#ifdef VTYSH
case VTYSH_SERV:
- vty_serv_thread = thread_add_read (vty_master, vtysh_accept, vty, sock);
+ vty_serv_thread = thread_add_read(vty_master, vtysh_accept, vty, sock, NULL);
vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
break;
case VTYSH_READ:
- vty->t_read = thread_add_read (vty_master, vtysh_read, vty, sock);
+ vty->t_read = NULL;
+ thread_add_read(vty_master, vtysh_read, vty, sock, &vty->t_read);
break;
case VTYSH_WRITE:
- vty->t_write = thread_add_write (vty_master, vtysh_write, vty, sock);
+ vty->t_write = NULL;
+ thread_add_write(vty_master, vtysh_write, vty, sock, &vty->t_write);
break;
#endif /* VTYSH */
case VTY_READ:
- vty->t_read = thread_add_read (vty_master, vty_read, vty, sock);
+ vty->t_read = NULL;
+ thread_add_read(vty_master, vty_read, vty, sock, &vty->t_read);
/* Time out treatment. */
if (vty->v_timeout)
{
if (vty->t_timeout)
thread_cancel (vty->t_timeout);
- vty->t_timeout =
- thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
+ vty->t_timeout = NULL;
+ thread_add_timer(vty_master, vty_timeout, vty, vty->v_timeout,
+ &vty->t_timeout);
}
break;
case VTY_WRITE:
- if (! vty->t_write)
- vty->t_write = thread_add_write (vty_master, vty_flush, vty, sock);
+ thread_add_write(vty_master, vty_flush, vty, sock, &vty->t_write);
break;
case VTY_TIMEOUT_RESET:
if (vty->t_timeout)
}
if (vty->v_timeout)
{
- vty->t_timeout =
- thread_add_timer (vty_master, vty_timeout, vty, vty->v_timeout);
+ vty->t_timeout = NULL;
+ thread_add_timer(vty_master, vty_timeout, vty, vty->v_timeout,
+ &vty->t_timeout);
}
break;
}
if ((v = vector_slot (vtyvec, i)) != NULL)
vty_out (vty, "%svty[%d] connected from %s.%s",
v->config ? "*" : " ",
- i, v->address, VTY_NEWLINE);
+ i, v->address, VTYNL);
return CMD_SUCCESS;
}
const char *accesslist = (argc == 3) ? argv[idx_word]->arg : NULL;
if (! vty_accesslist_name || (argc == 3 && strcmp(vty_accesslist_name, accesslist)))
{
- vty_out (vty, "Access-class is not currently applied to vty%s",
- VTY_NEWLINE);
- return CMD_WARNING;
+ vty_outln (vty,"Access-class is not currently applied to vty");
+ return CMD_WARNING_CONFIG_FAILED;
}
XFREE(MTYPE_VTY, vty_accesslist_name);
if (! vty_ipv6_accesslist_name ||
(argc == 4 && strcmp(vty_ipv6_accesslist_name, accesslist)))
{
- vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
- VTY_NEWLINE);
- return CMD_WARNING;
+ vty_outln (vty,"IPv6 access-class is not currently applied to vty");
+ return CMD_WARNING_CONFIG_FAILED;
}
XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
}
if (vty->hist[index] != NULL)
- vty_out (vty, " %s%s", vty->hist[index], VTY_NEWLINE);
+ vty_out (vty, " %s%s", vty->hist[index], VTYNL);
index++;
}
static int
vty_config_write (struct vty *vty)
{
- vty_out (vty, "line vty%s", VTY_NEWLINE);
+ vty_outln (vty, "line vty");
if (vty_accesslist_name)
- vty_out (vty, " access-class %s%s",
- vty_accesslist_name, VTY_NEWLINE);
+ vty_outln (vty, " access-class %s",
+ vty_accesslist_name);
if (vty_ipv6_accesslist_name)
- vty_out (vty, " ipv6 access-class %s%s",
- vty_ipv6_accesslist_name, VTY_NEWLINE);
+ vty_outln (vty, " ipv6 access-class %s",
+ vty_ipv6_accesslist_name);
/* exec-timeout */
if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
- vty_out (vty, " exec-timeout %ld %ld%s",
+ vty_outln (vty, " exec-timeout %ld %ld",
vty_timeout_val / 60,
- vty_timeout_val % 60, VTY_NEWLINE);
+ vty_timeout_val % 60);
/* login */
if (no_password_check)
- vty_out (vty, " no login%s", VTY_NEWLINE);
+ vty_outln (vty, " no login");
if (do_log_commands)
- vty_out (vty, "log commands%s", VTY_NEWLINE);
+ vty_outln (vty, "log commands");
- vty_out (vty, "!%s", VTY_NEWLINE);
+ vty_outln (vty, "!");
return CMD_SUCCESS;
}
Vvty_serv_thread = NULL;
}
}
-
-/* Utility functions to get arguments from commands generated
- by the xml2cli.pl script. */
-const char *
-vty_get_arg_value (struct vty_arg *args[], const char *arg)
-{
- while (*args)
- {
- if (strcmp ((*args)->name, arg) == 0)
- return (*args)->value;
- args++;
- }
- return NULL;
-}
-
-struct vty_arg *
-vty_get_arg (struct vty_arg *args[], const char *arg)
-{
- while (*args)
- {
- if (strcmp ((*args)->name, arg) == 0)
- return *args;
- args++;
- }
- return NULL;
-}