56 #include <arpa/telnet.h> 57 #include <sys/ioctl.h> 66 #define ANSI_CLEAR CSI "2J" CSI "1;1H" 68 #define ANSI_RESET CSI "0m" 70 #define ANSI_BOLD CSI "1m" 72 #define ANSI_DIM CSI "2m" 74 #define ANSI_DRED ANSI_DIM CSI "31m" 76 #define ANSI_BRED ANSI_BOLD CSI "31m" 78 #define ANSI_CLEARLINE CSI "2K" 80 #define ANSI_SCROLLDN CSI "1T" 82 #define ANSI_SAVECURSOR CSI "s" 84 #define ANSI_RESTCURSOR CSI "u" 88 #define UNIX_CLI_MAX_DEPTH_TELNET 24 91 #define UNIX_CLI_STDIN_FD 0 100 #define _(a) { .line = (u8 *)(a), .length = sizeof(a) - 1 } 103 _(
" _______ _ _ _____ ___ \n"),
104 _(
" __/ __/ _ \\ (_)__ | | / / _ \\/ _ \\\n"),
105 _(
" _/ _// // / / / _ \\ | |/ / ___/ ___/\n"),
106 _(
" /_/ /____(_)_/\\___/ |___/_/ /_/ \n"),
112 _(
ANSI_BRED " __/ __/ _ \\ (_)__ " ANSI_RESET
" | | / / _ \\/ _ \\\n"),
113 _(
ANSI_BRED " _/ _// // / / / _ \\" ANSI_RESET
" | |/ / ___/ ___/\n"),
114 _(
ANSI_BRED " /_/ /____(_)_/\\___/" ANSI_RESET
" |___/_/ /_/ \n"),
268 #define CTL(c) (u8[]){ (c) - '@', 0 } 270 #define _(a,b) { .input = (u8 *)(a), .len = sizeof(a) - 1, .action = (b) } 436 if (memcmp(input, a->
input, a->
len) == 0)
446 if (memcmp(input, a->
input, ilen) == 0)
512 for (i = 0; i < len; i++, str++)
545 if (n < 0 && errno != EAGAIN)
549 else if ((
word) n < (
word) buffer_bytes)
570 word end = 0, start = 0;
572 while (end < buffer_bytes)
579 buffer_bytes - start) + start;
591 if (end < buffer_bytes)
614 prompt =
format(0,
"\r%s-- more -- (%d-%d/%d)%s",
628 char *message,
char *postfix)
632 prompt =
format(0,
"\r%s-- %s --%s%s",
657 for (i = 0; i < cf->
width - 1; i ++)
703 uword i, len = buffer_bytes;
749 i < cf->pager_lines; i ++)
764 if (strncasecmp(a, (char *)term, (size_t)len) == 0) return 1; \ 805 for (i = 0; i < len; i++)
860 switch (input_vector[1])
886 if (input_vector[i - 1] == IAC && input_vector[i] == SE)
889 switch (input_vector[2])
892 if (input_vector[3] != 0)
907 cf->
width = clib_net_to_host_u16(*((
u16 *)(input_vector + 3)));
908 cf->
height = clib_net_to_host_u16(*((
u16 *)(input_vector + 5)));
920 if (i == UNIX_CLI_MAX_DEPTH_TELNET)
1014 for (j = cf->
cursor; j > delta; j--)
1258 else if (input ==
'D' -
'@')
1376 for (j = cf->
pager_start; j < cf->pager_lines && j < m; j ++)
1394 for (j = cf->
pager_start; j < cf->pager_lines && j < m; j ++)
1411 for (j = cf->
pager_start; j < cf->pager_lines; j ++)
1432 for (j = cf->
pager_start; j < cf->pager_lines && j < m; j ++)
1491 int k, limit, offset;
1509 for (offset = 0; offset <=
vec_len(item) - limit; offset++)
1511 for (k = 0; k < limit; k++)
1516 goto found_at_offset;
1547 else if (isprint(input))
1668 uword cli_file_index)
1698 lv =
format (lv,
"%U[%d]: %v",
1705 int rv __attribute__((unused)) =
1810 for (i = 0; i <
vec_len (data); i++)
1816 for (i = 0; i <
vec_len (data); i++)
1822 _vec_len (data) = 0;
1848 if (n < 0 && errno != EAGAIN)
1863 int n, n_read, n_try;
1868 while (n == n_try) {
1875 if (n < 0 && errno != EAGAIN)
1878 n_read = n < 0 ? 0 : n;
1906 name = (
char *)
format (0,
"unix-cli-%s", name);
1926 .process_log2_n_stack_bytes = 14,
1937 memset (cf, 0,
sizeof (*cf));
1941 template.file_descriptor = fd;
1991 u8 charmode_option[] = {
1992 IAC, WONT, TELOPT_LINEMODE,
1993 IAC, DONT, TELOPT_LINEMODE,
1994 IAC, WILL, TELOPT_SGA,
1995 IAC, DO, TELOPT_SGA,
1996 IAC, WILL, TELOPT_ECHO,
1997 IAC, DONT, TELOPT_ECHO,
1998 IAC, DO, TELOPT_TTYPE,
1999 IAC, SB, TELOPT_TTYPE, 1, IAC, SE,
2000 IAC, DO, TELOPT_NAWS,
2001 IAC, SB, TELOPT_NAWS, 1, IAC, SE,
2045 cf->
width = ws.ws_col;
2060 struct sigaction sa;
2086 if (sigaction (SIGWINCH, &sa, 0) < 0)
2091 cf->
width = ws.ws_col;
2115 tio.c_lflag &= ~(ECHO | ICANON | IEXTEN);
2117 tio.c_cc[VTIME] = 0;
2121 term = (
u8 *)getenv(
"TERM");
2124 strlen((
char *)term));
2142 if(s->config && s->config[0] != 0) {
2153 template.file_descriptor = s->fd;
2191 char * fmt = (prompt[strlen(prompt)-1] ==
' ') ?
"%s" :
"%s ";
2218 .short_help =
"Exit CLI",
2237 if (!
unformat (input,
"%s", &file_name))
2244 fd = open (file_name, O_RDONLY);
2255 if (fstat (fd, &s) < 0)
2261 if (! (S_ISREG (s.st_mode) || S_ISLNK (s.st_mode)))
2283 .short_help =
"Execute commands from file",
2296 int i, n_errors_to_show;
2299 n_errors_to_show = 1 << 30;
2303 if (!
unformat (input,
"%d", &n_errors_to_show))
2305 error =
clib_error_return (0,
"expecting integer number of errors to show, got `%U'",
2315 while (n_errors_to_show > 0)
2323 n_errors_to_show -= 1;
2330 if (
vec_len (unix_errors) == 0)
2335 for (i =
vec_len (unix_errors) - 1; i >= 0; i--)
2352 .path =
"show unix-errors",
2353 .short_help =
"Show Unix system call error history",
2385 .short_help =
"Show current session command history",
2417 cf->
no_pager || cf->
height ?
"" :
" (disabled by terminal height)",
2427 .path =
"show terminal",
2428 .short_help =
"Show current session terminal settings",
2452 else if (
unformat (line_input,
"off"))
2455 vlib_cli_output (vm,
"Pager limit set to %u lines; note, this is global.\n",
2468 .path =
"set terminal pager",
2469 .short_help =
"set terminal pager [on|off] [limit <lines>]",
2493 else if (
unformat (line_input,
"off"))
2517 .path =
"set terminal history",
2518 .short_help =
"set terminal history [on|off] [limit <lines>]",
2545 .path =
"set terminal ansi",
2546 .short_help =
"set terminal ansi [on|off]",
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
u32 history_limit
Maximum number of history entries this session will store.
u32 command_number
Current command line counter.
uword output_function_arg
u32 unix_file_index
The file index held by unix.c.
sll srl srl sll sra u16x4 i
static unix_cli_main_t unix_cli_main
CLI global state.
u32 pager_start
Line number of top of page.
always_inline uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
static unix_cli_parse_action_t unix_cli_match_action(unix_cli_parse_actions_t *a, u8 *input, u32 ilen, i32 *matched)
Search for a byte sequence in the action list.
u8 * input_vector
Vector of input saved by Unix input node to be processed by CLI process.
static clib_error_t * unix_cli_set_terminal_history(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI command to set terminal history settings.
static void(BVT(clib_bihash)*h, BVT(clib_bihash_value)*v)
always_inline vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
u8 * line
The line to print.
static void unix_vlib_cli_output(uword cli_file_index, u8 *buffer, uword buffer_bytes)
VLIB CLI output function.
u8 * format_clib_error(u8 *s, va_list *va)
#define ANSI_RESET
ANSI reset color settings.
static void unix_cli_add_pending_output(unix_file_t *uf, unix_cli_file_t *cf, u8 *buffer, uword buffer_bytes)
u32 pager_lines
Lines currently displayed.
Carriage return, newline or enter.
#define ANSI_RESTCURSOR
ANSI restore cursor position if previously saved.
u8 * cli_prompt
Prompt string for CLI.
static clib_error_t * unix_cli_set_terminal_pager(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI command to set terminal pager settings.
u32 cli_pager_buffer_limit
static clib_error_t * unix_cli_config(vlib_main_t *vm, unformat_input_t *input)
Handle configuration directives in the unix section.
always_inline uword unix_file_add(unix_main_t *um, unix_file_t *template)
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
static void unix_cli_ansi_cursor(unix_cli_file_t *cf, unix_file_t *uf, u16 x, u16 y)
Uses an ANSI escape sequence to move the cursor.
struct _vlib_node_registration vlib_node_registration_t
static clib_error_t * unix_cli_read_ready(unix_file_t *uf)
always_inline void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
#define VLIB_MAIN_LOOP_EXIT_CLI
#define vlib_call_config_function(vm, x)
void clib_longjmp(clib_longjmp_t *save, uword return_value)
add_epi add_epi sub_epi sub_epi adds_epu subs_epu i16x8 y
u32 cursor
Position of the insert cursor on the current input line.
clib_socket_t cli_listen_socket
#define ANSI_SCROLLDN
ANSI scroll screen down one line.
clib_error_t * clib_socket_init(clib_socket_t *s)
unix_cli_parse_action_t action
Action to take when matched.
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
u32 vlib_register_node(vlib_main_t *vm, vlib_node_registration_t *r)
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
static int unix_cli_line_edit(unix_cli_main_t *cm, unix_main_t *um, unix_cli_file_t *cf)
Process input bytes on a stream to provide line editing and command history in the CLI...
u8 ansi_capable
Can we do ANSI output?
static clib_error_t * unix_cli_set_terminal_ansi(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI command to set terminal ANSI settings.
static clib_error_t * unix_cli_init(vlib_main_t *vm)
#define CSI
ANSI Control Sequence Introducer.
static void unix_cli_cli_prompt(unix_cli_file_t *cf, unix_file_t *uf)
Output the CLI prompt.
struct _socket_t clib_socket_t
u8 * output_vector
Vector of output pending write to file descriptor.
#define VLIB_INIT_FUNCTION(x)
static clib_error_t * unix_cli_show_terminal(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI command to show terminal status.
#define vec_new(T, N)
Create new vector of given type and length (unspecified alignment, no header).
u32 len
Length of input without final NUL.
Mapping of input buffer strings to action values.
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
always_inline void vlib_node_set_state(vlib_main_t *vm, u32 node_index, vlib_node_state_t new_state)
static void unix_cli_pager_prompt(unix_cli_file_t *cf, unix_file_t *uf)
Output a pager prompt and show number of buffered lines.
always_inline void unix_cli_pager_reset(unix_cli_file_t *f)
Resets the pager buffer and other data.
u32 process_node_index
Process node identifier.
#define vec_resize(V, N)
Resize a vector (no header, unspecified alignment) Add N elements to end of given vector V...
static void unix_cli_del_pending_output(unix_file_t *uf, unix_cli_file_t *cf, uword n_bytes)
always_inline word unix_vlib_findchr(u8 chr, u8 *str, word len)
A bit like strchr with a buffer length limit.
u32 * unused_cli_process_node_indices
Vec pool of unused session indices.
#define UNIX_CLI_MAX_DEPTH_TELNET
Maximum depth into a byte stream from which to compile a Telnet protocol message. ...
static u32 unix_cli_file_add(unix_cli_main_t *cm, char *name, int fd)
Store a new CLI session.
static clib_error_t * unix_config(vlib_main_t *vm, unformat_input_t *input)
static uword unix_cli_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
static clib_error_t * unix_cli_listen_read_ready(unix_file_t *uf)
Telnet listening socket has a new connection.
unix_cli_file_t * cli_file_pool
Vec pool of CLI sessions.
#define pool_elt_at_index(p, i)
static clib_error_t * unix_show_errors(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI command to show various unix error statistics.
static u8 unix_cli_terminal_type(u8 *term, uword len)
Identify whether a terminal type is ANSI capable.
static void unix_vlib_cli_output_cooked(unix_cli_file_t *cf, unix_file_t *uf, u8 *buffer, uword buffer_bytes)
Process a buffer for CRLF handling before outputting it to the CLI.
void vlib_unix_cli_set_prompt(char *prompt)
Set the CLI prompt.
static void unix_cli_pager_prompt_erase(unix_cli_file_t *cf, unix_file_t *uf)
Erase the printed pager prompt.
always_inline uword * vlib_process_wait_for_event(vlib_main_t *vm)
static unix_cli_parse_actions_t unix_cli_parse_strings[]
Patterns to match on a CLI input stream.
#define clib_error_return_unix(e, args...)
void timer_call(timer_func_t *func, any arg, f64 dt)
#define VLIB_CONFIG_FUNCTION(x, n,...)
static clib_error_t * unix_cli_exec(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI command to execute a VPP command script.
u8 * input
Input string to match.
static unix_cli_banner_t unix_cli_banner[]
Plain welcome banner.
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
#define ANSI_BRED
ANSI Start bright red text.
unix_cli_process_event_type_t
CLI session events.
static i32 unix_cli_process_telnet(unix_main_t *um, unix_cli_file_t *cf, unix_file_t *uf, u8 *input_vector, uword len)
A mostly no-op Telnet state machine.
u8 ** pager_vector
Pager buffer.
unix_error_history_t error_history[128]
vlib_parse_match_t vlib_parse_eval(u8 *input)
#define ANSI_SAVECURSOR
ANSI save cursor position.
static void unix_vlib_cli_output_raw(unix_cli_file_t *cf, unix_file_t *uf, u8 *buffer, uword buffer_bytes)
Send a buffer to the CLI stream if possible, enqueue it otherwise.
u32 current_input_file_index
File pool index of current input.
#define ANSI_CLEARLINE
ANSI clear line cursor is on.
#define vec_free(V)
Free vector's memory (no header).
#define ANSI_BOLD
ANSI Start bold text.
#define VLIB_MAIN_LOOP_EXIT_FUNCTION(x)
#define clib_memcpy(a, b, c)
clib_error_t * clib_socket_accept(clib_socket_t *server, clib_socket_t *client)
#define clib_unix_warning(format, args...)
#define pool_is_free_index(P, I)
#define ANSI_CLEAR
ANSI clear screen.
static void unix_cli_file_welcome(unix_cli_main_t *cm, unix_cli_file_t *cf)
Emit initial welcome banner and prompt on a connection.
static void unix_cli_resize_interrupt(int signum)
The system terminal has informed us that the window size has changed.
#define CTL(c)
Given a capital ASCII letter character return a NUL terminated string with the control code for that ...
u8 no_pager
Disable the pager?
static unix_cli_banner_t unix_cli_banner_color[]
ANSI color welcome banner.
void vlib_start_process(vlib_main_t *vm, uword process_index)
#define VLIB_CLI_COMMAND(x,...)
static clib_error_t * unix_cli_quit(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI command to quit the terminal session.
always_inline void unix_file_del(unix_main_t *um, unix_file_t *f)
unix_cli_parse_action_t
CLI actions.
always_inline vlib_process_t * vlib_get_process_from_node(vlib_main_t *vm, vlib_node_t *node)
static void unix_cli_process_input(unix_cli_main_t *cm, uword cli_file_index)
Process input to a CLI session.
static void unix_cli_file_welcome_timer(any arg, f64 delay)
A failsafe triggered on a timer to ensure we send the prompt to telnet sessions that fail to negotiat...
#define vec_delete(V, N, M)
Delete N elements starting at element M.
A CLI session wants to close.
always_inline void clib_socket_free(clib_socket_t *s)
static clib_error_t * unix_cli_exit(vlib_main_t *vm)
Called when VPP is shutting down, this resets the system terminal state, if previously saved...
#define vec_append(v1, v2)
Append v2 after v1.
#define ESC
ANSI escape code.
u8 started
Has the session started?
static clib_error_t * unix_cli_write_ready(unix_file_t *uf)
#define UNIX_FLAG_INTERACTIVE
#define UNIX_FILE_DATA_AVAILABLE_TO_WRITE
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
#define UNIX_CLI_STDIN_FD
Unix standard in.
static void unix_cli_kill(unix_cli_main_t *cm, uword cli_file_index)
static void unix_cli_pager_message(unix_cli_file_t *cf, unix_file_t *uf, char *message, char *postfix)
Output a pager "skipping" message.
void(* file_update)(unix_file_t *file, unix_file_update_type_t update_type)
A file descriptor has data to be read.
static int unix_cli_line_process_one(unix_cli_main_t *cm, unix_main_t *um, unix_cli_file_t *cf, unix_file_t *uf, u8 input, unix_cli_parse_action_t action)
Process actionable input.
static clib_error_t * unix_cli_show_history(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI command to show session command history.
always_inline uword vlib_current_process(vlib_main_t *vm)
#define clib_panic(format, args...)
#define vec_foreach(var, vec)
Vector iterator.
u8 crlf_mode
Set if the CRLF mode wants CR + LF.
always_inline f64 vlib_time_now(vlib_main_t *vm)
#define clib_error_return(e, args...)
clib_longjmp_t main_loop_exit
vlib_cli_output_function_t * output_function
u8 line_mode
Line mode or char mode.
u32 length
The length of the line without terminating NUL.
void vlib_cli_input(vlib_main_t *vm, unformat_input_t *input, vlib_cli_output_function_t *function, uword function_arg)
u32 stdin_cli_file_index
The session index of the stdin cli.
always_inline void unix_cli_file_free(unix_cli_file_t *f)
Release storage used by a CLI session.
u32 height
Terminal height.