X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvlib%2Funix%2Fcli.c;h=cb13e0f09fa666ee7de47b7e6bf3c08eebc1ba34;hb=60529a8ef81d08c7aa0f7eaea402435b3c6d1eb6;hp=fa61c6964bea786fb7e36fa97550889c2e307c5a;hpb=6a3a4f7340bdc687814d7905ef1e4ca1a3b02d57;p=vpp.git diff --git a/src/vlib/unix/cli.c b/src/vlib/unix/cli.c index fa61c6964be..cb13e0f09fa 100644 --- a/src/vlib/unix/cli.c +++ b/src/vlib/unix/cli.c @@ -61,6 +61,8 @@ #include #include #include +#include +#include /** ANSI escape code. */ #define ESC "\x1b" @@ -91,7 +93,7 @@ /** Maximum depth into a byte stream from which to compile a Telnet * protocol message. This is a safety measure. */ -#define UNIX_CLI_MAX_DEPTH_TELNET 24 +#define UNIX_CLI_MAX_DEPTH_TELNET 32 /** Maximum terminal width we will accept */ #define UNIX_CLI_MAX_TERMINAL_WIDTH 512 @@ -241,6 +243,11 @@ typedef struct */ u8 cursor_direction; + /** Macro tables for this session */ + clib_macro_main_t macro_main; + + /** Session name */ + u8 *name; } unix_cli_file_t; /** Resets the pager buffer and other data. @@ -272,6 +279,7 @@ unix_cli_file_free (unix_cli_file_t * f) { vec_free (f->output_vector); vec_free (f->input_vector); + vec_free (f->name); unix_cli_pager_reset (f); } @@ -293,6 +301,7 @@ typedef enum UNIX_CLI_PARSE_ACTION_WORDRIGHT, /**< Jump cursor to start of right word */ UNIX_CLI_PARSE_ACTION_ERASELINELEFT, /**< Erase line to left of cursor */ UNIX_CLI_PARSE_ACTION_ERASELINERIGHT, /**< Erase line to right & including cursor */ + UNIX_CLI_PARSE_ACTION_ERASEWORDLEFT, /**< Erase word left */ UNIX_CLI_PARSE_ACTION_CLEAR, /**< Clear the terminal */ UNIX_CLI_PARSE_ACTION_REVSEARCH, /**< Search backwards in command history */ UNIX_CLI_PARSE_ACTION_FWDSEARCH, /**< Search forwards in command history */ @@ -359,6 +368,7 @@ static unix_cli_parse_actions_t unix_cli_parse_strings[] = { _(CTL ('D'), UNIX_CLI_PARSE_ACTION_ERASERIGHT), _(CTL ('U'), UNIX_CLI_PARSE_ACTION_ERASELINELEFT), _(CTL ('K'), UNIX_CLI_PARSE_ACTION_ERASELINERIGHT), + _(CTL ('W'), UNIX_CLI_PARSE_ACTION_ERASEWORDLEFT), _(CTL ('Y'), UNIX_CLI_PARSE_ACTION_YANK), _(CTL ('L'), UNIX_CLI_PARSE_ACTION_CLEAR), _(ESC "b", UNIX_CLI_PARSE_ACTION_WORDLEFT), /* Alt-B */ @@ -444,13 +454,6 @@ static unix_cli_parse_actions_t unix_cli_parse_pager[] = { #undef _ -/** CLI session events. */ -typedef enum -{ - UNIX_CLI_PROCESS_EVENT_READ_READY, /**< A file descriptor has data to be read. */ - UNIX_CLI_PROCESS_EVENT_QUIT, /**< A CLI session wants to close. */ -} unix_cli_process_event_type_t; - /** CLI session telnet negotiation timer events. */ typedef enum { @@ -489,11 +492,33 @@ typedef struct /** List of new sessions */ unix_cli_new_session_t *new_sessions; + + /** system default macro table */ + clib_macro_main_t macro_main; + } unix_cli_main_t; /** CLI global state */ static unix_cli_main_t unix_cli_main; +/** Return the macro main / tables we should use for this session + */ +static clib_macro_main_t * +get_macro_main (void) +{ + unix_cli_main_t *cm = &unix_cli_main; + vlib_main_t *vm = vlib_get_main (); + vlib_process_t *cp = vlib_get_current_process (vm); + unix_cli_file_t *cf; + + if (pool_is_free_index (cm->cli_file_pool, cp->output_function_arg)) + return (&cm->macro_main); + + cf = pool_elt_at_index (cm->cli_file_pool, cp->output_function_arg); + + return (&cf->macro_main); +} + /** * @brief Search for a byte sequence in the action list. * @@ -1236,9 +1261,9 @@ unix_cli_file_welcome (unix_cli_main_t * cm, unix_cli_file_t * cf) */ unix_cli_add_pending_output (uf, cf, (u8 *) "\r", 1); - if (!um->cli_no_banner) + if (!um->cli_no_banner && (um->flags & UNIX_FLAG_NOBANNER) == 0) { - if (cf->ansi_capable) + if (cf->ansi_capable && (um->flags & UNIX_FLAG_NOCOLOR) == 0) { banner = unix_cli_banner_color; len = ARRAY_LEN (unix_cli_banner_color); @@ -1292,6 +1317,10 @@ unix_cli_new_session_process (vlib_main_t * vm, vlib_node_runtime_t * rt, /* Add an identifier to the new session list */ unix_cli_new_session_t ns; + /* Check the connection didn't close already */ + if (pool_is_free_index (cm->cli_file_pool, event_data[0])) + break; + ns.cf_index = event_data[0]; ns.deadline = vlib_time_now (vm) + 1.0; @@ -1586,7 +1615,7 @@ unix_cli_line_process_one (unix_cli_main_t * cm, /* Delete the desired text from the command */ memmove (cf->current_command, cf->current_command + j, delta); - _vec_len (cf->current_command) = delta; + vec_set_len (cf->current_command, delta); /* Print the new contents */ unix_vlib_cli_output_cooked (cf, uf, cf->current_command, delta); @@ -1611,11 +1640,56 @@ unix_cli_line_process_one (unix_cli_main_t * cm, unix_vlib_cli_output_cursor_left (cf, uf); /* Truncate the line at the cursor */ - _vec_len (cf->current_command) = cf->cursor; + vec_set_len (cf->current_command, cf->cursor); cf->search_mode = 0; break; + case UNIX_CLI_PARSE_ACTION_ERASEWORDLEFT: + /* calculate num of caracter to be erased */ + delta = 0; + while (cf->cursor > delta + && cf->current_command[cf->cursor - delta - 1] == ' ') + delta++; + while (cf->cursor > delta + && cf->current_command[cf->cursor - delta - 1] != ' ') + delta++; + + if (vec_len (cf->current_command)) + { + if (cf->cursor > 0) + { + /* move cursor left delta times */ + for (j = delta; j > 0; j--, cf->cursor--) + unix_vlib_cli_output_cursor_left (cf, uf); + save = cf->current_command + cf->cursor; + + /* redraw remainder of line */ + memmove (cf->current_command + cf->cursor, + cf->current_command + cf->cursor + delta, + _vec_len (cf->current_command) - cf->cursor - delta); + unix_vlib_cli_output_cooked (cf, uf, + cf->current_command + cf->cursor, + _vec_len (cf->current_command) - + cf->cursor); + cf->cursor += _vec_len (cf->current_command) - cf->cursor; + + /* print delta amount of blank spaces, + * then finally fix the cursor position */ + for (j = delta; j > 0; j--, cf->cursor--) + unix_vlib_cli_output_cursor_left (cf, uf); + for (j = delta; j > 0; j--, cf->cursor++) + unix_vlib_cli_output_cooked (cf, uf, (u8 *) " ", 1); + for (; (cf->current_command + cf->cursor) > save; cf->cursor--) + unix_vlib_cli_output_cursor_left (cf, uf); + vec_dec_len (cf->current_command, delta); + } + } + cf->search_mode = 0; + cf->excursion = 0; + vec_reset_length (cf->search_key); + break; + case UNIX_CLI_PARSE_ACTION_LEFT: if (cf->cursor > 0) { @@ -1665,13 +1739,13 @@ unix_cli_line_process_one (unix_cli_main_t * cm, if (cf->excursion == vec_len (cf->command_history)) { /* down-arrowed to last entry - want a blank line */ - _vec_len (cf->current_command) = 0; + vec_set_len (cf->current_command, 0); } else if (cf->excursion < 0) { /* up-arrowed over the start to the end, want a blank line */ cf->excursion = vec_len (cf->command_history); - _vec_len (cf->current_command) = 0; + vec_set_len (cf->current_command, 0); } else { @@ -1684,7 +1758,7 @@ unix_cli_line_process_one (unix_cli_main_t * cm, vec_validate (cf->current_command, vec_len (prev) - 1); clib_memcpy (cf->current_command, prev, vec_len (prev)); - _vec_len (cf->current_command) = vec_len (prev); + vec_set_len (cf->current_command, vec_len (prev)); unix_vlib_cli_output_cooked (cf, uf, cf->current_command, vec_len (cf->current_command)); } @@ -1771,7 +1845,7 @@ unix_cli_line_process_one (unix_cli_main_t * cm, cf->cursor++; unix_vlib_cli_output_cursor_left (cf, uf); cf->cursor--; - _vec_len (cf->current_command)--; + vec_dec_len (cf->current_command, 1); } else if (cf->cursor > 0) { @@ -1779,7 +1853,7 @@ unix_cli_line_process_one (unix_cli_main_t * cm, j = vec_len (cf->current_command) - cf->cursor; memmove (cf->current_command + cf->cursor - 1, cf->current_command + cf->cursor, j); - _vec_len (cf->current_command)--; + vec_dec_len (cf->current_command, 1); /* redraw the rest of the line */ unix_vlib_cli_output_cursor_left (cf, uf); @@ -1815,7 +1889,7 @@ unix_cli_line_process_one (unix_cli_main_t * cm, j = vec_len (cf->current_command) - cf->cursor - 1; memmove (cf->current_command + cf->cursor, cf->current_command + cf->cursor + 1, j); - _vec_len (cf->current_command)--; + vec_dec_len (cf->current_command, 1); /* redraw the rest of the line */ unix_vlib_cli_output_cooked (cf, uf, cf->current_command + cf->cursor, @@ -1887,7 +1961,7 @@ unix_cli_line_process_one (unix_cli_main_t * cm, vec_resize (save, vec_len (cf->current_command) - cf->cursor); clib_memcpy (save, cf->current_command + cf->cursor, vec_len (cf->current_command) - cf->cursor); - _vec_len (cf->current_command) = cf->cursor; + vec_set_len (cf->current_command, cf->cursor); } else { @@ -1909,7 +1983,7 @@ unix_cli_line_process_one (unix_cli_main_t * cm, cf->cursor--; j--; } - _vec_len (cf->current_command) = j; + vec_set_len (cf->current_command, j); /* replace it with the newly expanded command */ vec_append (cf->current_command, completed); @@ -2316,7 +2390,7 @@ unix_cli_line_process_one (unix_cli_main_t * cm, vec_validate (cf->current_command, vec_len (item) - 1); clib_memcpy (cf->current_command, item, vec_len (item)); - _vec_len (cf->current_command) = vec_len (item); + vec_set_len (cf->current_command, vec_len (item)); unix_vlib_cli_output_cooked (cf, uf, cf->current_command, vec_len (cf->current_command)); @@ -2448,6 +2522,7 @@ unix_cli_line_edit (unix_cli_main_t * cm, unix_main_t * um, if (cf->line_mode) { vec_delete (cf->input_vector, i, 0); + vec_free (cf->current_command); cf->current_command = cf->input_vector; return 0; } @@ -2506,13 +2581,34 @@ more: { static u8 *lv; vec_reset_length (lv); - lv = format (lv, "%U[%d]: %v", - format_timeval, 0 /* current bat-time */ , - 0 /* current bat-format */ , + lv = format (lv, "%U[%d]: %v", format_timeval, + NULL /* current bat-format */, 0 /* current bat-time */, cli_file_index, cf->current_command); + if ((vec_len (cf->current_command) > 0) && + (cf->current_command[vec_len (cf->current_command) - 1] != '\n')) + lv = format (lv, "\n"); int rv __attribute__ ((unused)) = write (um->log_fd, lv, vec_len (lv)); } + /* Run the command through the macro processor */ + if (vec_len (cf->current_command)) + { + u8 *expanded; + vec_validate (cf->current_command, vec_len (cf->current_command)); + cf->current_command[vec_len (cf->current_command) - 1] = 0; + /* The macro expander expects proper C-strings, not vectors */ + expanded = (u8 *) clib_macro_eval (&cf->macro_main, + (i8 *) cf->current_command, + 1 /* complain */ , + 0 /* level */ , + 8 /* max_level */ ); + /* Macro processor NULL terminates the return */ + vec_dec_len (expanded, 1); + vec_reset_length (cf->current_command); + vec_append (cf->current_command, expanded); + vec_free (expanded); + } + /* Build an unformat structure around our command */ unformat_init_vector (&input, cf->current_command); @@ -2599,6 +2695,17 @@ unix_cli_kill (unix_cli_main_t * cm, uword cli_file_index) if (pool_is_free_index (cm->cli_file_pool, cli_file_index)) return; + vec_foreach_index (i, cm->new_sessions) + { + unix_cli_new_session_t *ns = vec_elt_at_index (cm->new_sessions, i); + + if (ns->cf_index == cli_file_index) + { + ns->cf_index = ~0; + break; + } + } + cf = pool_elt_at_index (cm->cli_file_pool, cli_file_index); uf = pool_elt_at_index (fm->file_pool, cf->clib_file_index); @@ -2613,10 +2720,12 @@ unix_cli_kill (unix_cli_main_t * cm, uword cli_file_index) vec_free (cf->command_history[i]); vec_free (cf->command_history); + vec_free (cf->input_vector); clib_file_del (fm, uf); unix_cli_file_free (cf); + clib_macro_free (&cf->macro_main); pool_put (cm->cli_file_pool, cf); } @@ -2649,7 +2758,7 @@ unix_cli_process (vlib_main_t * vm, } if (data) - _vec_len (data) = 0; + vec_set_len (data, 0); } done: @@ -2731,7 +2840,7 @@ unix_cli_read_ready (clib_file_t * uf) return clib_error_return_unix (0, "read"); n_read = n < 0 ? 0 : n; - _vec_len (cf->input_vector) = l + n_read; + vec_set_len (cf->input_vector, l + n_read); } if (!(n < 0)) @@ -2777,75 +2886,48 @@ unix_cli_file_add (unix_cli_main_t * cm, char *name, int fd) clib_file_t template = { 0 }; vlib_main_t *vm = um->vlib_main; vlib_node_t *n = 0; - u8 *file_desc = 0; - - file_desc = format (0, "%s", name); - - name = (char *) format (0, "unix-cli-%s", name); if (vec_len (cm->unused_cli_process_node_indices) > 0) { - uword l = vec_len (cm->unused_cli_process_node_indices); - int i; - vlib_main_t *this_vlib_main; - u8 *old_name = 0; - - /* - * Nodes are bulk-copied, so node name pointers are shared. - * Find the cli node in all graph replicas, and give all of them - * the same new name. - * Then, throw away the old shared name-vector. - */ - for (i = 0; i < vec_len (vlib_mains); i++) - { - this_vlib_main = vlib_mains[i]; - if (this_vlib_main == 0) - continue; - n = vlib_get_node (this_vlib_main, - cm->unused_cli_process_node_indices[l - 1]); - old_name = n->name; - n->name = (u8 *) name; - } - vec_free (old_name); + n = vlib_get_node (vm, vec_pop (cm->unused_cli_process_node_indices)); vlib_node_set_state (vm, n->index, VLIB_NODE_STATE_POLLING); - - _vec_len (cm->unused_cli_process_node_indices) = l - 1; } else { static vlib_node_registration_t r = { .function = unix_cli_process, .type = VLIB_NODE_TYPE_PROCESS, - .process_log2_n_stack_bytes = 16, + .process_log2_n_stack_bytes = 18, }; - - r.name = name; + static u32 count = 0; vlib_worker_thread_barrier_sync (vm); - vlib_register_node (vm, &r); - vec_free (name); + vlib_register_node (vm, &r, "unix-cli-process-%u", count++); n = vlib_get_node (vm, r.index); vlib_worker_thread_node_runtime_update (); vlib_worker_thread_barrier_release (vm); } - pool_get (cm->cli_file_pool, cf); - clib_memset (cf, 0, sizeof (*cf)); + pool_get_zero (cm->cli_file_pool, cf); + clib_macro_init (&cf->macro_main); template.read_function = unix_cli_read_ready; template.write_function = unix_cli_write_ready; template.error_function = unix_cli_error_detected; template.file_descriptor = fd; template.private_data = cf - cm->cli_file_pool; - template.description = file_desc; + template.description = format (0, "%s", name); + cf->name = format (0, "unix-cli-%s", name); cf->process_node_index = n->index; cf->clib_file_index = clib_file_add (fm, &template); cf->output_vector = 0; cf->input_vector = 0; + vec_validate (cf->current_command, 0); + vec_set_len (cf->current_command, 0); vlib_start_process (vm, n->runtime_index); @@ -3042,9 +3124,11 @@ unix_cli_config (vlib_main_t * vm, unformat_input_t * input) clib_panic ("sigaction"); /* Retrieve the current terminal size */ - ioctl (STDIN_FILENO, TIOCGWINSZ, &ws); - cf->width = ws.ws_col; - cf->height = ws.ws_row; + if (ioctl (STDIN_FILENO, TIOCGWINSZ, &ws) == 0) + { + cf->width = ws.ws_col; + cf->height = ws.ws_row; + } if (cf->width == 0 || cf->height == 0) { @@ -3120,7 +3204,7 @@ unix_cli_config (vlib_main_t * vm, unformat_input_t * input) while (i && tmp[--i] != '/') ; - tmp[i] = 0; + tmp[i] = '\0'; if (i) vlib_unix_recursive_mkdir ((char *) tmp); @@ -3185,6 +3269,23 @@ vlib_unix_cli_set_prompt (char *prompt) cm->cli_prompt = format (0, fmt, prompt); } +static unix_cli_file_t * +unix_cli_file_if_exists (unix_cli_main_t * cm) +{ + if (!cm->cli_file_pool) + return 0; + return pool_elt_at_index (cm->cli_file_pool, cm->current_input_file_index); +} + +static unix_cli_file_t * +unix_cli_file_if_interactive (unix_cli_main_t * cm) +{ + unix_cli_file_t *cf; + if ((cf = unix_cli_file_if_exists (cm)) && !cf->is_interactive) + return 0; + return cf; +} + /** CLI command to quit the terminal session. * @note If this is a stdin session then this will * shutdown VPP also. @@ -3194,8 +3295,10 @@ unix_cli_quit (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { unix_cli_main_t *cm = &unix_cli_main; - unix_cli_file_t *cf = pool_elt_at_index (cm->cli_file_pool, - cm->current_input_file_index); + unix_cli_file_t *cf; + + if (!(cf = unix_cli_file_if_exists (cm))) + return clib_error_return (0, "invalid session"); /* Cosmetic: suppress the final prompt from appearing before we die */ cf->is_interactive = 0; @@ -3236,13 +3339,18 @@ unix_cli_exec (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { char *file_name; - int fd; - unformat_input_t sub_input; + int fd, rv = 0; + unformat_input_t sub_input, in; clib_error_t *error; - + clib_macro_main_t *mm = 0; + unix_cli_main_t *cm = &unix_cli_main; + unix_cli_file_t *cf; + u8 *file_data = 0; file_name = 0; fd = -1; error = 0; + struct stat s; + if (!unformat (input, "%s", &file_name)) { @@ -3259,29 +3367,76 @@ unix_cli_exec (vlib_main_t * vm, } /* Make sure its a regular file. */ - { - struct stat s; + if (fstat (fd, &s) < 0) + { + error = clib_error_return_unix (0, "failed to stat `%s'", file_name); + goto done; + } - if (fstat (fd, &s) < 0) - { - error = clib_error_return_unix (0, "failed to stat `%s'", file_name); - goto done; - } + if (!(S_ISREG (s.st_mode) || S_ISLNK (s.st_mode))) + { + error = clib_error_return (0, "not a regular file `%s'", file_name); + goto done; + } - if (!(S_ISREG (s.st_mode) || S_ISLNK (s.st_mode))) - { - error = clib_error_return (0, "not a regular file `%s'", file_name); - goto done; - } - } + if (s.st_size < 1) + { + error = clib_error_return (0, "empty file `%s'", file_name); + goto done; + } - unformat_init_clib_file (&sub_input, fd); + /* Read the file */ + vec_validate (file_data, s.st_size - 1); + + if (read (fd, file_data, s.st_size) != s.st_size) + { + error = clib_error_return_unix (0, "Failed to read %d bytes from '%s'", + s.st_size, file_name); + vec_free (file_data); + goto done; + } + + unformat_init_vector (&sub_input, file_data); + + /* Initial config process? Use the global macro table. */ + if (pool_is_free_index (cm->cli_file_pool, cm->current_input_file_index)) + mm = &cm->macro_main; + else + { + /* Otherwise, use the per-cli-process macro table */ + cf = pool_elt_at_index (cm->cli_file_pool, cm->current_input_file_index); + mm = &cf->macro_main; + } + + while (rv == 0 && unformat_user (&sub_input, unformat_vlib_cli_line, &in)) + { + /* Run the file contents through the macro processor */ + if (vec_len (in.buffer) > 1) + { + u8 *expanded; + + /* The macro expander expects a c string... */ + vec_add1 (in.buffer, 0); + + expanded = + (u8 *) clib_macro_eval (mm, (i8 *) in.buffer, 1 /* complain */, + 0 /* level */, 8 /* max_level */); + /* Macro processor NULL terminates the return */ + vec_dec_len (expanded, 1); + vec_reset_length (in.buffer); + vec_append (in.buffer, expanded); + vec_free (expanded); + } - vlib_cli_input (vm, &sub_input, 0, 0); + if ((rv = vlib_cli_input (vm, &in, 0, 0)) != 0) + error = clib_error_return (0, "CLI line error: %U", + format_unformat_error, &in); + unformat_free (&in); + } unformat_free (&sub_input); done: - if (fd > 0) + if (fd >= 0) close (fd); vec_free (file_name); @@ -3290,7 +3445,7 @@ done: /*? * Executes a sequence of CLI commands which are read from a file. If - * a command is unrecognised or otherwise invalid then the usual CLI + * a command is unrecognized or otherwise invalid then the usual CLI * feedback will be generated, however execution of subsequent commands * from the file will continue. * @@ -3410,7 +3565,7 @@ unix_show_files (vlib_main_t * vm, "Read", "Write", "Error", "File Name", "Description"); /* *INDENT-OFF* */ - pool_foreach (f, fm->file_pool,( + pool_foreach (f, fm->file_pool) { int rv; s = format (s, "/proc/self/fd/%d%c", f->file_descriptor, 0); @@ -3423,7 +3578,7 @@ unix_show_files (vlib_main_t * vm, f->read_events, f->write_events, f->error_events, path, f->description); vec_reset_length (s); - })); + } /* *INDENT-ON* */ vec_free (s); @@ -3447,9 +3602,7 @@ unix_cli_show_history (vlib_main_t * vm, unix_cli_file_t *cf; int i, j; - cf = pool_elt_at_index (cm->cli_file_pool, cm->current_input_file_index); - - if (!cf->is_interactive) + if (!(cf = unix_cli_file_if_interactive (cm))) return clib_error_return (0, "invalid for non-interactive sessions"); if (cf->has_history && cf->history_limit) @@ -3487,10 +3640,13 @@ unix_cli_show_terminal (vlib_main_t * vm, unix_cli_file_t *cf; vlib_node_t *n; - cf = pool_elt_at_index (cm->cli_file_pool, cm->current_input_file_index); + if (!(cf = unix_cli_file_if_exists (cm))) + return clib_error_return (0, "invalid session"); + n = vlib_get_node (vm, cf->process_node_index); - vlib_cli_output (vm, "Terminal name: %v\n", n->name); + vlib_cli_output (vm, "Terminal name: %v\n", cf->name); + vlib_cli_output (vm, "Terminal node: %v\n", n->name); vlib_cli_output (vm, "Terminal mode: %s\n", cf->line_mode ? "line-by-line" : "char-by-char"); vlib_cli_output (vm, "Terminal width: %d\n", cf->width); @@ -3555,31 +3711,34 @@ unix_cli_show_cli_sessions (vlib_main_t * vm, { unix_cli_main_t *cm = &unix_cli_main; clib_file_main_t *fm = &file_main; + table_t table = {}, *t = &table; unix_cli_file_t *cf; clib_file_t *uf; - vlib_node_t *n; - vlib_cli_output (vm, "%-5s %-5s %-20s %s", "PNI", "FD", "Name", "Flags"); + table_add_header_col (t, 4, "PNI ", "FD ", "Name", "Flags"); #define fl(x, y) ( (x) ? toupper((y)) : tolower((y)) ) - /* *INDENT-OFF* */ - pool_foreach (cf, cm->cli_file_pool, ({ - uf = pool_elt_at_index (fm->file_pool, cf->clib_file_index); - n = vlib_get_node (vm, cf->process_node_index); - vlib_cli_output (vm, - "%-5d %-5d %-20v %c%c%c%c%c\n", - cf->process_node_index, - uf->file_descriptor, - n->name, - fl (cf->is_interactive, 'i'), - fl (cf->is_socket, 's'), - fl (cf->line_mode, 'l'), - fl (cf->has_epipe, 'p'), - fl (cf->ansi_capable, 'a')); - })); - /* *INDENT-ON* */ + int i = 0; + pool_foreach (cf, cm->cli_file_pool) + { + int j = 0; + + uf = pool_elt_at_index (fm->file_pool, cf->clib_file_index); + table_format_cell (t, i, j++, "%u", cf->process_node_index); + table_format_cell (t, i, j++, "%u", uf->file_descriptor); + table_format_cell (t, i, j++, "%v", cf->name); + table_format_cell (t, i++, j++, "%c%c%c%c%c", + fl (cf->is_interactive, 'i'), fl (cf->is_socket, 's'), + fl (cf->line_mode, 'l'), fl (cf->has_epipe, 'p'), + fl (cf->ansi_capable, 'a')); + } #undef fl + t->default_body.align = TTAA_LEFT; + t->default_header_col.align = TTAA_LEFT; + vlib_cli_output (vm, "%U", format_table, t); + table_free (t); + return 0; } @@ -3639,9 +3798,7 @@ unix_cli_set_terminal_pager (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; clib_error_t *error = 0; - cf = pool_elt_at_index (cm->cli_file_pool, cm->current_input_file_index); - - if (!cf->is_interactive) + if (!(cf = unix_cli_file_if_interactive (cm))) return clib_error_return (0, "invalid for non-interactive sessions"); if (!unformat_user (input, unformat_line_input, line_input)) @@ -3698,9 +3855,7 @@ unix_cli_set_terminal_history (vlib_main_t * vm, u32 limit; clib_error_t *error = 0; - cf = pool_elt_at_index (cm->cli_file_pool, cm->current_input_file_index); - - if (!cf->is_interactive) + if (!(cf = unix_cli_file_if_interactive (cm))) return clib_error_return (0, "invalid for non-interactive sessions"); if (!unformat_user (input, unformat_line_input, line_input)) @@ -3768,9 +3923,7 @@ unix_cli_set_terminal_ansi (vlib_main_t * vm, unix_cli_main_t *cm = &unix_cli_main; unix_cli_file_t *cf; - cf = pool_elt_at_index (cm->cli_file_pool, cm->current_input_file_index); - - if (!cf->is_interactive) + if (!(cf = unix_cli_file_if_interactive (cm))) return clib_error_return (0, "invalid for non-interactive sessions"); if (unformat (input, "on")) @@ -3800,6 +3953,161 @@ VLIB_CLI_COMMAND (cli_unix_cli_set_terminal_ansi, static) = { }; /* *INDENT-ON* */ + +#define MAX_CLI_WAIT 86400 +/** CLI command to wait seconds. Useful for exec script. */ +static clib_error_t * +unix_wait_cmd (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + f64 sec = 1.0; + + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%f", &sec)) + ; + else + return clib_error_return (0, "unknown parameter: `%U`", + format_unformat_error, input); + } + + if (sec <= 0 || sec > MAX_CLI_WAIT || floor (sec * 1000) / 1000 != sec) + return clib_error_return (0, + " must be a positive value and less than 86400 (one day) with no more than msec precision."); + + vlib_process_wait_for_event_or_clock (vm, sec); + vlib_cli_output (vm, "waited %.3f sec.", sec); + + unformat_free (line_input); + return 0; +} +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (cli_unix_wait_cmd, static) = { + .path = "wait", + .short_help = "wait ", + .function = unix_wait_cmd, +}; +/* *INDENT-ON* */ + +static clib_error_t * +echo_cmd (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + { + vlib_cli_output (vm, ""); + return 0; + } + + vlib_cli_output (vm, "%v", line_input->buffer); + + unformat_free (line_input); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (cli_unix_echo_cmd, static) = { + .path = "echo", + .short_help = "echo ", + .function = echo_cmd, +}; +/* *INDENT-ON* */ + +static clib_error_t * +define_cmd_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + u8 *macro_name; + unformat_input_t _line_input, *line_input = &_line_input; + clib_macro_main_t *mm = get_macro_main (); + clib_error_t *error; + + if (!unformat (input, "%s", ¯o_name)) + return clib_error_return (0, "missing variable name..."); + + /* Remove white space */ + (void) unformat (input, ""); + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + { + error = clib_error_return (0, "missing value for '%s'...", macro_name); + vec_free (macro_name); + return error; + } + /* the macro expander expects c-strings, not vectors... */ + vec_add1 (line_input->buffer, 0); + clib_macro_set_value (mm, (char *) macro_name, (char *) line_input->buffer); + vec_free (macro_name); + unformat_free (line_input); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (define_cmd, static) = { + .path = "define", + .short_help = "define ", + .function = define_cmd_fn, +}; + +/* *INDENT-ON* */ + +static clib_error_t * +undefine_cmd_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + u8 *macro_name; + clib_macro_main_t *mm = get_macro_main (); + + if (!unformat (input, "%s", ¯o_name)) + return clib_error_return (0, "missing variable name..."); + + if (clib_macro_unset (mm, (char *) macro_name)) + vlib_cli_output (vm, "%s wasn't set...", macro_name); + + vec_free (macro_name); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (undefine_cmd, static) = { + .path = "undefine", + .short_help = "undefine ", + .function = undefine_cmd_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +show_macro_cmd_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + clib_macro_main_t *mm = get_macro_main (); + int evaluate = 1; + + if (unformat (input, "noevaluate %=", &evaluate, 0)) + ; + else if (unformat (input, "noeval %=", &evaluate, 0)) + ; + + vlib_cli_output (vm, "%U", format_clib_macro_main, mm, evaluate); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_macro, static) = { + .path = "show macro", + .short_help = "show macro [noevaluate]", + .function = show_macro_cmd_fn, +}; +/* *INDENT-ON* */ + static clib_error_t * unix_cli_init (vlib_main_t * vm) { @@ -3808,6 +4116,7 @@ unix_cli_init (vlib_main_t * vm) /* Breadcrumb to indicate the new session process * has not been started */ cm->new_session_process_node_index = ~0; + clib_macro_init (&cm->macro_main); return 0; }