aboutsummaryrefslogtreecommitdiffstats
path: root/src/vty/vty.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vty/vty.c')
-rw-r--r--src/vty/vty.c138
1 files changed, 109 insertions, 29 deletions
diff --git a/src/vty/vty.c b/src/vty/vty.c
index ebdf9fc9..3a549b43 100644
--- a/src/vty/vty.c
+++ b/src/vty/vty.c
@@ -66,6 +66,8 @@
#include <osmocom/vty/command.h>
#include <osmocom/vty/buffer.h>
#include <osmocom/core/talloc.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/utils.h>
#ifndef MAXPATHLEN
#define MAXPATHLEN 4096
@@ -206,6 +208,12 @@ static void vty_auth(struct vty *vty)
}
}
+void vty_flush(struct vty *vty)
+{
+ if (vty->obuf)
+ buffer_flush_all(vty->obuf, vty->fd);
+}
+
/*! Close a given vty interface. */
void vty_close(struct vty *vty)
{
@@ -331,6 +339,25 @@ int vty_out_newline(struct vty *vty)
return 0;
}
+/*! calculates the time difference of a give timespec to the current time
+ * and prints in a human readable format (days, hours, minutes, seconds).
+ */
+int vty_out_uptime(struct vty *vty, const struct timespec *starttime)
+{
+ struct timespec now;
+ struct timespec uptime;
+
+ osmo_clock_gettime(CLOCK_MONOTONIC, &now);
+ timespecsub(&now, starttime, &uptime);
+
+ int d = uptime.tv_sec / (3600 * 24);
+ int h = uptime.tv_sec / 3600 % 24;
+ int m = uptime.tv_sec / 60 % 60;
+ int s = uptime.tv_sec % 60;
+
+ return vty_out(vty, "%dd %dh %dm %ds", d, h, m, s);
+}
+
/*! return the current index of a given VTY */
void *vty_current_index(struct vty *vty)
{
@@ -458,6 +485,7 @@ static int vty_command(struct vty *vty)
static const char telnet_backward_char = 0x08;
static const char telnet_space_char = ' ';
+static const char telnet_escape_char = 0x1B;
/* Basic function to write buffer to vty. */
static void vty_write(struct vty *vty, const char *buf, size_t nbytes)
@@ -857,6 +885,19 @@ static void vty_down_level(struct vty *vty)
vty->cp = 0;
}
+/* When '^L' is typed, clear all lines above the current one. */
+static void vty_clear_screen(struct vty *vty)
+{
+ vty_out(vty, "%c%s%c%s",
+ telnet_escape_char,
+ "[2J", /* Erase Screen */
+ telnet_escape_char,
+ "[H" /* Cursor Home */
+ );
+ vty_prompt(vty);
+ vty_redraw_line(vty);
+}
+
/* When '^Z' is received from vty, move down to the enable mode. */
static void vty_end_config(struct vty *vty)
{
@@ -1119,7 +1160,7 @@ static void vty_describe_command(struct vty *vty)
int ret;
vector vline;
vector describe;
- unsigned int i, width, desc_width;
+ unsigned int i, cmd_width, desc_width;
struct desc *desc, *desc_cr = NULL;
vline = cmd_make_strvec(vty->buf);
@@ -1143,19 +1184,17 @@ static void vty_describe_command(struct vty *vty)
vty_prompt(vty);
vty_redraw_line(vty);
return;
- 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;
- break;
}
/* Get width of command string. */
- width = 0;
- for (i = 0; i < vector_active(describe); i++)
+ cmd_width = 0;
+ for (i = 0; i < vector_active(describe); i++) {
if ((desc = vector_slot(describe, i)) != NULL) {
unsigned int len;
@@ -1166,15 +1205,16 @@ static void vty_describe_command(struct vty *vty)
if (desc->cmd[0] == '.')
len--;
- if (width < len)
- width = len;
+ if (cmd_width < len)
+ cmd_width = len;
}
+ }
/* Get width of description string. */
- desc_width = vty->width - (width + 6);
+ desc_width = vty->width - (cmd_width + 6);
/* Print out description. */
- for (i = 0; i < vector_active(describe); i++)
+ for (i = 0; i < vector_active(describe); i++) {
if ((desc = vector_slot(describe, i)) != NULL) {
if (desc->cmd[0] == '\0')
continue;
@@ -1190,19 +1230,20 @@ static void vty_describe_command(struct vty *vty)
'.' ? desc->cmd + 1 : desc->cmd,
VTY_NEWLINE);
else if (desc_width >= strlen(desc->str))
- vty_out(vty, " %-*s %s%s", width,
+ vty_out(vty, " %-*s %s%s", cmd_width,
desc->cmd[0] ==
'.' ? desc->cmd + 1 : desc->cmd,
desc->str, VTY_NEWLINE);
else
- vty_describe_fold(vty, width, desc_width, desc);
+ vty_describe_fold(vty, cmd_width, desc_width, desc);
#if 0
- vty_out(vty, " %-*s %s%s", width
+ vty_out(vty, " %-*s %s%s", cmd_width
desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
desc->str ? desc->str : "", VTY_NEWLINE);
#endif /* 0 */
}
+ }
if ((desc = desc_cr)) {
if (!desc->str)
@@ -1210,11 +1251,11 @@ static void vty_describe_command(struct vty *vty)
desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
VTY_NEWLINE);
else if (desc_width >= strlen(desc->str))
- vty_out(vty, " %-*s %s%s", width,
+ vty_out(vty, " %-*s %s%s", cmd_width,
desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
desc->str, VTY_NEWLINE);
else
- vty_describe_fold(vty, width, desc_width, desc);
+ vty_describe_fold(vty, cmd_width, desc_width, desc);
}
cmd_free_strvec(vline);
@@ -1401,6 +1442,9 @@ int vty_read(struct vty *vty)
case CONTROL('K'):
vty_kill_line(vty);
break;
+ case CONTROL('L'):
+ vty_clear_screen(vty);
+ break;
case CONTROL('N'):
vty_next_line(vty);
break;
@@ -1461,9 +1505,13 @@ int vty_read(struct vty *vty)
return 0;
}
-/* Read up configuration file */
-static int
-vty_read_file(FILE *confp, void *priv)
+/* Read up configuration from a file stream */
+/*! Read up VTY configuration from a file stream
+ * \param[in] confp file pointer of the stream for the configuration file
+ * \param[in] priv private data to be passed to \ref vty_read_file
+ * \returns Zero on success, non-zero on error
+ */
+int vty_read_config_filep(FILE *confp, void *priv)
{
int ret;
struct vty *vty;
@@ -1794,6 +1842,8 @@ void vty_init_vtysh(void)
/* Install vty's own commands like `who' command. */
void vty_init(struct vty_app_info *app_info)
{
+ unsigned int i, j;
+
tall_vty_ctx = talloc_named_const(NULL, 0, "vty");
tall_vty_vec_ctx = talloc_named_const(tall_vty_ctx, 0, "vty_vector");
tall_vty_cmd_ctx = talloc_named_const(tall_vty_ctx, 0, "vty_command");
@@ -1802,6 +1852,36 @@ void vty_init(struct vty_app_info *app_info)
host.app_info = app_info;
+ /* Check for duplicate flags in application specific attributes (if any) */
+ for (i = 0; i < ARRAY_SIZE(app_info->usr_attr_letters); i++) {
+ if (app_info->usr_attr_letters[i] == '\0')
+ continue;
+
+ /* Some flag characters are reserved for global attributes */
+ const char rafc[] = VTY_CMD_ATTR_FLAGS_RESERVED;
+ for (j = 0; j < ARRAY_SIZE(rafc); j++) {
+ if (app_info->usr_attr_letters[i] != rafc[j])
+ continue;
+ fprintf(stderr, "Attribute flag character '%c' is reserved "
+ "for globals! Please fix.\n", app_info->usr_attr_letters[i]);
+ }
+
+ /* Upper case flag letters are reserved for libraries */
+ if (app_info->usr_attr_letters[i] >= 'A' &&
+ app_info->usr_attr_letters[i] <= 'Z') {
+ fprintf(stderr, "Attribute flag letter '%c' is reserved "
+ "for libraries! Please fix.\n", app_info->usr_attr_letters[i]);
+ }
+
+ for (j = i + 1; j < ARRAY_SIZE(app_info->usr_attr_letters); j++) {
+ if (app_info->usr_attr_letters[j] != app_info->usr_attr_letters[i])
+ continue;
+ fprintf(stderr, "Found duplicate flag letter '%c' in application "
+ "specific attributes (index %u vs %u)! Please fix.\n",
+ app_info->usr_attr_letters[i], i, j);
+ }
+ }
+
/* For further configuration read, preserve current directory. */
vty_save_cwd();
@@ -1810,18 +1890,18 @@ void vty_init(struct vty_app_info *app_info)
/* Install bgp top node. */
install_node(&vty_node, vty_config_write);
- install_element_ve(&config_who_cmd);
- install_element_ve(&show_history_cmd);
- install_element(CONFIG_NODE, &line_vty_cmd);
- install_element(CONFIG_NODE, &service_advanced_vty_cmd);
- install_element(CONFIG_NODE, &no_service_advanced_vty_cmd);
- install_element(CONFIG_NODE, &show_history_cmd);
- install_element(ENABLE_NODE, &terminal_monitor_cmd);
- install_element(ENABLE_NODE, &terminal_no_monitor_cmd);
+ install_lib_element_ve(&config_who_cmd);
+ install_lib_element_ve(&show_history_cmd);
+ install_lib_element(CONFIG_NODE, &line_vty_cmd);
+ install_lib_element(CONFIG_NODE, &service_advanced_vty_cmd);
+ install_lib_element(CONFIG_NODE, &no_service_advanced_vty_cmd);
+ install_lib_element(CONFIG_NODE, &show_history_cmd);
+ install_lib_element(ENABLE_NODE, &terminal_monitor_cmd);
+ install_lib_element(ENABLE_NODE, &terminal_no_monitor_cmd);
- install_element(VTY_NODE, &vty_login_cmd);
- install_element(VTY_NODE, &no_vty_login_cmd);
- install_element(VTY_NODE, &vty_bind_cmd);
+ install_lib_element(VTY_NODE, &vty_login_cmd);
+ install_lib_element(VTY_NODE, &no_vty_login_cmd);
+ install_lib_element(VTY_NODE, &vty_bind_cmd);
}
/*! Read the configuration file using the VTY code
@@ -1837,7 +1917,7 @@ int vty_read_config_file(const char *file_name, void *priv)
if (!cfile)
return -ENOENT;
- rc = vty_read_file(cfile, priv);
+ rc = vty_read_config_filep(cfile, priv);
fclose(cfile);
host_config_set(file_name);