58 #include <arpa/telnet.h> 59 #include <sys/ioctl.h> 68 #define ANSI_CLEAR CSI "2J" CSI "1;1H" 70 #define ANSI_RESET CSI "0m" 72 #define ANSI_BOLD CSI "1m" 74 #define ANSI_DIM CSI "2m" 76 #define ANSI_DRED ANSI_DIM CSI "31m" 78 #define ANSI_BRED ANSI_BOLD CSI "31m" 80 #define ANSI_CLEARLINE CSI "2K" 82 #define ANSI_SCROLLDN CSI "1T" 84 #define ANSI_SAVECURSOR CSI "s" 86 #define ANSI_RESTCURSOR CSI "u" 90 #define UNIX_CLI_MAX_DEPTH_TELNET 24 93 #define UNIX_CLI_STDIN_FD 0 103 #define _(a) { .line = (u8 *)(a), .length = sizeof(a) - 1 } 106 _(
" _______ _ _ _____ ___ \n"),
107 _(
" __/ __/ _ \\ (_)__ | | / / _ \\/ _ \\\n"),
108 _(
" _/ _// // / / / _ \\ | |/ / ___/ ___/\n"),
109 _(
" /_/ /____(_)_/\\___/ |___/_/ /_/ \n"),
116 _(
ANSI_BRED " __/ __/ _ \\ (_)__ " ANSI_RESET
" | | / / _ \\/ _ \\\n"),
117 _(
ANSI_BRED " _/ _// // / / / _ \\" ANSI_RESET
" | |/ / ___/ ___/\n"),
118 _(
ANSI_BRED " /_/ /____(_)_/\\___/" ANSI_RESET
" |___/_/ /_/ \n"),
303 #define CTL(c) (u8[]){ (c) - '@', 0 } 305 #define _(a,b) { .input = (u8 *)(a), .len = sizeof(a) - 1, .action = (b) } 466 u8 * input,
u32 ilen,
i32 * matched)
476 if (memcmp (input, a->
input, a->
len) == 0)
486 if (memcmp (input, a->
input, ilen) == 0)
505 u8 * buffer,
uword buffer_bytes)
556 for (i = 0; i < len; i++, str++)
588 if (n < 0 && errno != EAGAIN)
592 else if ((
word) n < (
word) buffer_bytes)
612 u8 * buffer,
uword buffer_bytes)
614 word end = 0, start = 0;
616 while (end < buffer_bytes)
623 buffer_bytes - start) + start;
635 if (end < buffer_bytes)
665 prompt =
format (0,
"\r%s-- more -- (%d-%d/%d)%s",
680 char *message,
char *postfix)
684 prompt =
format (0,
"\r%s-- %s --%s%s",
709 for (i = 0; i < cf->
width - 1; i++)
757 for (i = 0; i < cf->
height - 1 &&
766 if (pi && line[pi->
length - 1] !=
'\n')
798 word line_index, len;
805 line_index = len_or_index;
828 if (j < l && p[j] ==
'\n')
836 pi->
line = line_index;
857 word i, old_line, old_offset;
888 if (pi->
line == old_line &&
956 if (row < cf->height - 1)
965 if (line[pi->
length - 1] !=
'\n' && row == cf->
height - 2)
1019 if (strncasecmp(a, (char *)term, (size_t)len) == 0) return 1; \ 1024 _(
"xterm-256color");
1053 len =
ARRAY_LEN (unix_cli_banner_color);
1061 for (i = 0; i < len; i++)
1064 banner[i].line, banner[i].length);
1115 switch (input_vector[1])
1129 if (
vec_len (input_vector) < 3)
1141 if (input_vector[i - 1] == IAC && input_vector[i] == SE)
1144 switch (input_vector[2])
1147 if (input_vector[3] != 0)
1163 clib_net_to_host_u16 (*((
u16 *) (input_vector + 3)));
1165 clib_net_to_host_u16 (*((
u16 *) (input_vector + 5)));
1181 if (i == UNIX_CLI_MAX_DEPTH_TELNET)
1275 for (j = cf->
cursor; j > delta; j--)
1519 else if (input ==
'D' -
'@')
1587 if (pi && line[pi->
length - 1] !=
'\n')
1613 if (line[pi->
length - 1] !=
'\n')
1664 if (pi && line[pi->
length - 1] !=
'\n')
1689 if (pi && line[pi->
length - 1] !=
'\n')
1712 if (pi && line[pi->
length - 1] !=
'\n')
1740 if (pi && line[pi->
length - 1] !=
'\n')
1821 for (offset = 0; offset <=
vec_len (item) - limit; offset++)
1823 for (k = 0; k < limit; k++)
1828 goto found_at_offset;
1859 else if (isprint (input))
2013 lv =
format (lv,
"%U[%d]: %v",
2018 int rv __attribute__ ((unused)) =
2129 for (i = 0; i <
vec_len (data); i++)
2135 for (i = 0; i <
vec_len (data); i++)
2141 _vec_len (data) = 0;
2170 if (n < 0 && errno != EAGAIN)
2187 int n, n_read, n_try;
2200 if (n < 0 && errno != EAGAIN)
2203 n_read = n < 0 ? 0 : n;
2232 name = (
char *)
format (0,
"unix-cli-%s", name);
2252 .process_log2_n_stack_bytes = 16,
2263 memset (cf, 0,
sizeof (*cf));
2267 template.file_descriptor = fd;
2318 u8 charmode_option[] = {
2319 IAC, WONT, TELOPT_LINEMODE,
2320 IAC, DONT, TELOPT_LINEMODE,
2321 IAC, WILL, TELOPT_SGA,
2322 IAC, DO, TELOPT_SGA,
2323 IAC, WILL, TELOPT_ECHO,
2324 IAC, DONT, TELOPT_ECHO,
2325 IAC, DO, TELOPT_TTYPE,
2326 IAC, SB, TELOPT_TTYPE, 1, IAC, SE,
2327 IAC, DO, TELOPT_NAWS,
2328 IAC, SB, TELOPT_NAWS, 1, IAC, SE,
2380 cf->
width = ws.ws_col;
2401 struct sigaction sa;
2425 memset (&sa, 0,
sizeof (sa));
2427 if (sigaction (SIGWINCH, &sa, 0) < 0)
2432 cf->
width = ws.ws_col;
2456 tio.c_lflag &= ~(ECHO | ICANON | IEXTEN);
2458 tio.c_cc[VTIME] = 0;
2462 term = (
u8 *) getenv (
"TERM");
2484 if (s->config && s->config[0] != 0)
2496 template.file_descriptor = s->fd;
2538 char *fmt = (prompt[strlen (prompt) - 1] ==
' ') ?
"%s" :
"%s ";
2571 .short_help =
"Exit CLI",
2590 if (!
unformat (input,
"%s", &file_name))
2597 fd = open (file_name, O_RDONLY);
2608 if (fstat (fd, &s) < 0)
2614 if (!(S_ISREG (s.st_mode) || S_ISLNK (s.st_mode)))
2644 .short_help =
"Execute commands from file",
2657 int i, n_errors_to_show;
2660 n_errors_to_show = 1 << 30;
2664 if (!
unformat (input,
"%d", &n_errors_to_show))
2668 "expecting integer number of errors to show, got `%U'",
2681 while (n_errors_to_show > 0)
2689 n_errors_to_show -= 1;
2696 if (
vec_len (unix_errors) == 0)
2701 for (i =
vec_len (unix_errors) - 1; i >= 0; i--)
2719 .path =
"show unix-errors",
2720 .short_help =
"Show Unix system call error history",
2756 .short_help =
"Show current session command history",
2776 "line-by-line" :
"char-by-char");
2784 " (disabled by history limit)");
2790 || cf->
height ?
"" :
" (disabled by terminal height)",
2793 " (disabled by buffer limit)");
2822 .path =
"show terminal",
2823 .short_help =
"Show current session terminal settings",
2849 else if (
unformat (line_input,
"off"))
2853 "Pager limit set to %u lines; note, this is global.\n",
2878 .path =
"set terminal pager",
2879 .short_help =
"set terminal pager [on|off] [limit <lines>]",
2905 else if (
unformat (line_input,
"off"))
2941 .path =
"set terminal history",
2942 .short_help =
"set terminal history [on|off] [limit <lines>]",
2979 .path =
"set terminal ansi",
2980 .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) ...
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.
u32 history_limit
Maximum number of history entries this session will store.
u32 command_number
Current command line counter.
uword output_function_arg
#define vec_foreach_index(var, v)
Iterate over vector indices.
u8 * format_clib_error(u8 *s, va_list *va)
u32 unix_file_index
The file index held by unix.c.
#define UNIX_CLI_MAX_DEPTH_TELNET
Maximum depth into a byte stream from which to compile a Telnet protocol message. ...
sll srl srl sll sra u16x4 i
u32 pager_start
Line number of top of page.
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.
Action parser found a partial match.
Carriage return, newline or enter.
Search forwards in command history.
unix_cli_process_event_type_t
CLI session events.
u8 * input_vector
Vector of input saved by Unix input node to be processed by CLI process.
static uword * vlib_process_wait_for_event(vlib_main_t *vm)
void vlib_cli_input(vlib_main_t *vm, unformat_input_t *input, vlib_cli_output_function_t *function, uword function_arg)
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.
static uword vlib_current_process(vlib_main_t *vm)
#define CTL(c)
Given a capital ASCII letter character return a NUL terminated string with the control code for that ...
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 * line
The line to print.
u8 * cli_prompt
Prompt string for CLI.
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.
u32 cli_pager_buffer_limit
u8 ** command_history
Array of vectors of commands in the history.
static void unix_vlib_cli_output(uword cli_file_index, u8 *buffer, uword buffer_bytes)
VLIB CLI output function.
static f64 vlib_time_now(vlib_main_t *vm)
void vlib_unix_cli_set_prompt(char *prompt)
Set the CLI prompt.
static void unix_cli_file_free(unix_cli_file_t *f)
Release storage used by a CLI session.
static u32 unix_cli_file_add(unix_cli_main_t *cm, char *name, int fd)
Store a new CLI session.
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
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.
unix_cli_pager_index_t * pager_index
Index of line fragments in the pager buffer.
struct _vlib_node_registration vlib_node_registration_t
u8 * current_command
The command currently pointed at by the history cursor.
#define UNIX_CLI_STDIN_FD
Unix standard in.
#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
clib_error_t * clib_socket_init(clib_socket_t *s)
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
unix_cli_parse_action_t action
Action to take when matched.
static clib_error_t * unix_cli_init(vlib_main_t *vm)
static void unix_cli_del_pending_output(unix_file_t *uf, unix_cli_file_t *cf, uword n_bytes)
Delete all bytes from the output vector and flag the I/O system that no more bytes are available to b...
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
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.
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
u8 ansi_capable
Can we do ANSI output?
static void unix_cli_pager_reindex(unix_cli_file_t *cf)
Reindex entire pager buffer.
A CLI session wants to close.
struct _socket_t clib_socket_t
u8 * output_vector
Vector of output pending write to file descriptor.
#define VLIB_INIT_FUNCTION(x)
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
static void unix_cli_add_pending_output(unix_file_t *uf, unix_cli_file_t *cf, u8 *buffer, uword buffer_bytes)
Add bytes to the output vector and then flagg the I/O system that bytes are available to be sent...
End key (jump to end of line)
#define vec_new(T, N)
Create new vector of given type and length (unspecified alignment, no header).
Jump cursor to start of right word.
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.
#define clib_error_return(e, args...)
#define ANSI_SCROLLDN
ANSI scroll screen down one line.
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...
Erase line to right & including cursor.
#define ANSI_CLEARLINE
ANSI clear line cursor is on.
u32 * unused_cli_process_node_indices
Vec pool of unused session indices.
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.
unix_cli_file_t * cli_file_pool
Vec pool of CLI sessions.
static uword unix_file_add(unix_main_t *um, unix_file_t *template)
int search_mode
If non-zero then the CLI is searching in the history array.
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
#define ANSI_RESTCURSOR
ANSI restore cursor position if previously saved.
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.
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
static clib_error_t * unix_config(vlib_main_t *vm, unformat_input_t *input)
static void unix_cli_pager_reset(unix_cli_file_t *f)
Resets the pager buffer and other data.
static clib_error_t * unix_cli_listen_read_ready(unix_file_t *uf)
Telnet listening socket has a new connection.
#define clib_error_return_unix(e, args...)
Home key (jump to start of line)
#define pool_put(P, E)
Free an object E in pool P.
#define ANSI_BOLD
ANSI Start bold text.
static unix_cli_banner_t unix_cli_banner[]
Plain welcome banner.
void timer_call(timer_func_t *func, any arg, f64 dt)
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.
#define VLIB_CONFIG_FUNCTION(x, n,...)
Search backwards in command history.
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...
static void clib_socket_free(clib_socket_t *s)
u8 * input
Input string to match.
u32 node_index
Node index.
Erase line to left of cursor.
#define CSI
ANSI Control Sequence Introducer.
u8 ** pager_vector
Pager buffer.
unix_error_history_t error_history[128]
vlib_parse_match_t vlib_parse_eval(u8 *input)
static unix_cli_banner_t unix_cli_banner_color[]
ANSI color welcome banner.
u32 current_input_file_index
File pool index of current input.
#define vec_free(V)
Free vector's memory (no header).
#define VLIB_MAIN_LOOP_EXIT_FUNCTION(x)
static void unix_cli_cli_prompt(unix_cli_file_t *cf, unix_file_t *uf)
Output the CLI prompt.
#define ANSI_SAVECURSOR
ANSI save cursor position.
#define clib_memcpy(a, b, c)
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.
clib_error_t * clib_socket_accept(clib_socket_t *server, clib_socket_t *client)
static clib_error_t * unix_cli_write_ready(unix_file_t *uf)
Called when a CLI session file descriptor can be written to without blocking.
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
A file descriptor has data to be read.
#define ESC
ANSI escape code.
Jump cursor to start of left word.
#define UNIX_FILE_DATA_AVAILABLE_TO_WRITE
void vlib_start_process(vlib_main_t *vm, uword process_index)
u8 no_pager
Disable the pager?
#define VLIB_CLI_COMMAND(x,...)
static void unix_cli_pager_prompt_erase(unix_cli_file_t *cf, unix_file_t *uf)
Erase the printed pager prompt.
Enter pressed (CR, CRLF, LF, etc)
static clib_error_t * unix_cli_read_ready(unix_file_t *uf)
Called when a CLI session file descriptor has data to be read.
static void unix_cli_kill(unix_cli_main_t *cm, uword cli_file_index)
Destroy a CLI session.
#define vec_delete(V, N, M)
Delete N elements starting at element M.
static word unix_vlib_findchr(u8 chr, u8 *str, word len)
A bit like strchr with a buffer length limit.
unix_cli_parse_action_t
CLI actions.
u32 vlib_register_node(vlib_main_t *vm, vlib_node_registration_t *r)
#define UNIX_FLAG_INTERACTIVE
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.
static clib_error_t * unix_cli_config(vlib_main_t *vm, unformat_input_t *input)
Handle configuration directives in the unix section.
#define vec_append(v1, v2)
Append v2 after v1.
static void vlib_node_set_state(vlib_main_t *vm, u32 node_index, vlib_node_state_t new_state)
Set node dispatch state.
u8 has_history
This session has command history.
#define ANSI_CLEAR
ANSI clear screen.
static u8 unix_cli_terminal_type(u8 *term, uword len)
Identify whether a terminal type is ANSI capable.
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.
Action parser did not find any match.
u8 started
Has the session started?
void(* file_update)(unix_file_t *file, unix_file_update_type_t update_type)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
#define ANSI_BRED
ANSI Start bright red text.
u8 * search_key
The string being searched for in the history.
#define clib_unix_warning(format, args...)
static void unix_cli_pager_redraw(unix_cli_file_t *cf, unix_file_t *uf)
Redraw the currently displayed page of text.
static uword unix_cli_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Handle system events.
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.
struct clib_bihash_value offset
template key/value backing page structure
static vlib_process_t * vlib_get_process_from_node(vlib_main_t *vm, vlib_node_t *node)
static void unix_cli_resize_interrupt(int signum)
The system terminal has informed us that the window size has changed.
Clear and redraw the page on the terminal.
static vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Get vlib node by index.
#define vec_foreach(var, vec)
Vector iterator.
static void unix_cli_pager_message(unix_cli_file_t *cf, unix_file_t *uf, char *message, char *postfix)
Output a pager "skipping" message.
u8 crlf_mode
Set if the CRLF mode wants CR + LF.
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.
#define ANSI_RESET
ANSI reset color settings.
clib_longjmp_t main_loop_exit
vlib_cli_output_function_t * output_function
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.
static unix_cli_main_t unix_cli_main
CLI global state.
i32 excursion
How far from the end of the history array the user has browsed.
u8 line_mode
Line mode or char mode.
u32 length
The length of the line without terminating NUL.
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
u32 stdin_cli_file_index
The session index of the stdin cli.
static void unix_cli_pager_add_line(unix_cli_file_t *cf, u8 *line, word len_or_index)
Process and add a line to the pager index.
#define clib_panic(format, args...)
u32 height
Terminal height.
static void unix_file_del(unix_main_t *um, unix_file_t *f)
static clib_error_t * unix_cli_exit(vlib_main_t *vm)
Called when VPP is shutting down, this restores the system terminal state if previously saved...
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...
static void unix_cli_process_input(unix_cli_main_t *cm, uword cli_file_index)
Process input to a CLI session.
static unix_cli_parse_actions_t unix_cli_parse_strings[]
Patterns to match on a CLI input stream.