diff options
Diffstat (limited to 'src/vty/vty.c')
-rw-r--r-- | src/vty/vty.c | 138 |
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); |