1 /*
2 * Copyright (c) 2018 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <ctype.h>
8 #include <stdlib.h>
9 #include <zephyr/sys/atomic.h>
10 #include <zephyr/shell/shell.h>
11 #if defined(CONFIG_SHELL_BACKEND_DUMMY)
12 #include <zephyr/shell/shell_dummy.h>
13 #endif
14 #include "shell_ops.h"
15 #include "shell_help.h"
16 #include "shell_utils.h"
17 #include "shell_vt100.h"
18 #include "shell_wildcard.h"
19
20 /* 2 == 1 char for cmd + 1 char for '\0' */
21 #if (CONFIG_SHELL_CMD_BUFF_SIZE < 2)
22 #error too small CONFIG_SHELL_CMD_BUFF_SIZE
23 #endif
24
25 #if (CONFIG_SHELL_PRINTF_BUFF_SIZE < 1)
26 #error too small SHELL_PRINTF_BUFF_SIZE
27 #endif
28
29 #define SHELL_MSG_CMD_NOT_FOUND ": command not found"
30 #define SHELL_MSG_BACKEND_NOT_ACTIVE \
31 "WARNING: A print request was detected on not active shell backend.\n"
32 #define SHELL_MSG_TOO_MANY_ARGS "Too many arguments in the command.\n"
33 #define SHELL_INIT_OPTION_PRINTER (NULL)
34
35 #define SHELL_THREAD_PRIORITY \
36 COND_CODE_1(CONFIG_SHELL_THREAD_PRIORITY_OVERRIDE, \
37 (CONFIG_SHELL_THREAD_PRIORITY), (K_LOWEST_APPLICATION_THREAD_PRIO))
38
39 BUILD_ASSERT(SHELL_THREAD_PRIORITY >=
40 K_HIGHEST_APPLICATION_THREAD_PRIO
41 && SHELL_THREAD_PRIORITY <= K_LOWEST_APPLICATION_THREAD_PRIO,
42 "Invalid range for thread priority");
43
receive_state_change(const struct shell * sh,enum shell_receive_state state)44 static inline void receive_state_change(const struct shell *sh,
45 enum shell_receive_state state)
46 {
47 sh->ctx->receive_state = state;
48 }
49
cmd_buffer_clear(const struct shell * sh)50 static void cmd_buffer_clear(const struct shell *sh)
51 {
52 sh->ctx->cmd_buff[0] = '\0'; /* clear command buffer */
53 sh->ctx->cmd_buff_pos = 0;
54 sh->ctx->cmd_buff_len = 0;
55 }
56
shell_internal_help_print(const struct shell * sh)57 static void shell_internal_help_print(const struct shell *sh)
58 {
59 if (!IS_ENABLED(CONFIG_SHELL_HELP)) {
60 return;
61 }
62
63 z_shell_help_cmd_print(sh, &sh->ctx->active_cmd);
64 z_shell_help_subcmd_print(sh, &sh->ctx->active_cmd,
65 "Subcommands:\n");
66 }
67
68 /**
69 * @brief Prints error message on wrong argument count.
70 * Optionally, printing help on wrong argument count.
71 *
72 * @param[in] shell Pointer to the shell instance.
73 * @param[in] arg_cnt_ok Flag indicating valid number of arguments.
74 *
75 * @return 0 if check passed
76 * @return -EINVAL if wrong argument count
77 */
cmd_precheck(const struct shell * sh,bool arg_cnt_ok)78 static int cmd_precheck(const struct shell *sh,
79 bool arg_cnt_ok)
80 {
81 if (!arg_cnt_ok) {
82 z_shell_fprintf(sh, SHELL_ERROR,
83 "%s: wrong parameter count\n",
84 sh->ctx->active_cmd.syntax);
85
86 if (IS_ENABLED(CONFIG_SHELL_HELP_ON_WRONG_ARGUMENT_COUNT)) {
87 shell_internal_help_print(sh);
88 }
89
90 return -EINVAL;
91 }
92
93 return 0;
94 }
95
state_set(const struct shell * sh,enum shell_state state)96 static inline void state_set(const struct shell *sh, enum shell_state state)
97 {
98 sh->ctx->state = state;
99
100 if (state == SHELL_STATE_ACTIVE && !sh->ctx->bypass) {
101 cmd_buffer_clear(sh);
102 if (z_flag_print_noinit_get(sh)) {
103 z_shell_fprintf(sh, SHELL_WARNING, "%s",
104 SHELL_MSG_BACKEND_NOT_ACTIVE);
105 z_flag_print_noinit_set(sh, false);
106 }
107 z_shell_print_prompt_and_cmd(sh);
108 }
109 }
110
state_get(const struct shell * sh)111 static inline enum shell_state state_get(const struct shell *sh)
112 {
113 return sh->ctx->state;
114 }
115
116 static inline const struct shell_static_entry *
selected_cmd_get(const struct shell * sh)117 selected_cmd_get(const struct shell *sh)
118 {
119 if (IS_ENABLED(CONFIG_SHELL_CMDS_SELECT)
120 || (CONFIG_SHELL_CMD_ROOT[0] != 0)) {
121 return sh->ctx->selected_cmd;
122 }
123
124 return NULL;
125 }
126
tab_item_print(const struct shell * sh,const char * option,uint16_t longest_option)127 static void tab_item_print(const struct shell *sh, const char *option,
128 uint16_t longest_option)
129 {
130 static const char *tab = " ";
131 uint16_t columns;
132 uint16_t diff;
133
134 /* Function initialization has been requested. */
135 if (option == NULL) {
136 sh->ctx->vt100_ctx.printed_cmd = 0;
137 return;
138 }
139
140 longest_option += z_shell_strlen(tab);
141
142 columns = (sh->ctx->vt100_ctx.cons.terminal_wid
143 - z_shell_strlen(tab)) / longest_option;
144 diff = longest_option - z_shell_strlen(option);
145
146 if (sh->ctx->vt100_ctx.printed_cmd++ % columns == 0U) {
147 z_shell_fprintf(sh, SHELL_OPTION, "\n%s%s", tab, option);
148 } else {
149 z_shell_fprintf(sh, SHELL_OPTION, "%s", option);
150 }
151
152 z_shell_op_cursor_horiz_move(sh, diff);
153 }
154
history_init(const struct shell * sh)155 static void history_init(const struct shell *sh)
156 {
157 if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
158 return;
159 }
160
161 z_shell_history_init(sh->history);
162 }
163
history_purge(const struct shell * sh)164 static void history_purge(const struct shell *sh)
165 {
166 if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
167 return;
168 }
169
170 z_shell_history_purge(sh->history);
171 }
172
history_mode_exit(const struct shell * sh)173 static void history_mode_exit(const struct shell *sh)
174 {
175 if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
176 return;
177 }
178
179 z_flag_history_exit_set(sh, false);
180 z_shell_history_mode_exit(sh->history);
181 }
182
history_put(const struct shell * sh,uint8_t * line,size_t length)183 static void history_put(const struct shell *sh, uint8_t *line, size_t length)
184 {
185 if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
186 return;
187 }
188
189 z_shell_history_put(sh->history, line, length);
190 }
191
history_handle(const struct shell * sh,bool up)192 static void history_handle(const struct shell *sh, bool up)
193 {
194 bool history_mode;
195 uint16_t len;
196
197 /*optional feature */
198 if (!IS_ENABLED(CONFIG_SHELL_HISTORY)) {
199 return;
200 }
201
202 /* Checking if history process has been stopped */
203 if (z_flag_history_exit_get(sh)) {
204 z_flag_history_exit_set(sh, false);
205 z_shell_history_mode_exit(sh->history);
206 }
207
208 /* Backup command if history is entered */
209 if (!z_shell_history_active(sh->history)) {
210 if (up) {
211 uint16_t cmd_len = z_shell_strlen(sh->ctx->cmd_buff);
212
213 if (cmd_len) {
214 strcpy(sh->ctx->temp_buff,
215 sh->ctx->cmd_buff);
216 } else {
217 sh->ctx->temp_buff[0] = '\0';
218 }
219 } else {
220 /* Pressing 'down' not in history mode has no effect. */
221 return;
222 }
223 }
224
225 /* Start by checking if history is not empty. */
226 history_mode = z_shell_history_get(sh->history, up,
227 sh->ctx->cmd_buff, &len);
228
229 /* On exiting history mode print backed up command. */
230 if (!history_mode) {
231 strcpy(sh->ctx->cmd_buff, sh->ctx->temp_buff);
232 len = z_shell_strlen(sh->ctx->cmd_buff);
233 }
234
235 z_shell_op_cursor_home_move(sh);
236 z_clear_eos(sh);
237 z_shell_print_cmd(sh);
238 sh->ctx->cmd_buff_pos = len;
239 sh->ctx->cmd_buff_len = len;
240 z_shell_op_cond_next_line(sh);
241 }
242
completion_space_get(const struct shell * sh)243 static inline uint16_t completion_space_get(const struct shell *sh)
244 {
245 uint16_t space = (CONFIG_SHELL_CMD_BUFF_SIZE - 1) -
246 sh->ctx->cmd_buff_len;
247 return space;
248 }
249
250 /* Prepare arguments and return number of space available for completion. */
tab_prepare(const struct shell * sh,const struct shell_static_entry ** cmd,const char *** argv,size_t * argc,size_t * complete_arg_idx,struct shell_static_entry * d_entry)251 static bool tab_prepare(const struct shell *sh,
252 const struct shell_static_entry **cmd,
253 const char ***argv, size_t *argc,
254 size_t *complete_arg_idx,
255 struct shell_static_entry *d_entry)
256 {
257 uint16_t compl_space = completion_space_get(sh);
258 size_t search_argc;
259
260 if (compl_space == 0U) {
261 return false;
262 }
263
264 /* Copy command from its beginning to cursor position. */
265 memcpy(sh->ctx->temp_buff, sh->ctx->cmd_buff,
266 sh->ctx->cmd_buff_pos);
267 sh->ctx->temp_buff[sh->ctx->cmd_buff_pos] = '\0';
268
269 /* Create argument list. */
270 (void)z_shell_make_argv(argc, *argv, sh->ctx->temp_buff,
271 CONFIG_SHELL_ARGC_MAX);
272
273 if (*argc > CONFIG_SHELL_ARGC_MAX) {
274 return false;
275 }
276
277 /* terminate arguments with NULL */
278 (*argv)[*argc] = NULL;
279
280 if ((IS_ENABLED(CONFIG_SHELL_CMDS_SELECT) || (CONFIG_SHELL_CMD_ROOT[0] != 0))
281 && (*argc > 0) &&
282 (strcmp("select", (*argv)[0]) == 0) &&
283 !z_shell_in_select_mode(sh)) {
284 *argv = *argv + 1;
285 *argc = *argc - 1;
286 }
287
288 /* If last command is not completed (followed by space) it is treated
289 * as uncompleted one.
290 */
291 int space = (sh->ctx->cmd_buff_pos > 0) ?
292 isspace((int)sh->ctx->cmd_buff[sh->ctx->cmd_buff_pos - 1]) : 0;
293
294 /* root command completion */
295 if ((*argc == 0) || ((space == 0) && (*argc == 1))) {
296 *complete_arg_idx = Z_SHELL_CMD_ROOT_LVL;
297 *cmd = selected_cmd_get(sh);
298 return true;
299 }
300
301 search_argc = space ? *argc : *argc - 1;
302
303 *cmd = z_shell_get_last_command(selected_cmd_get(sh), search_argc,
304 *argv, complete_arg_idx, d_entry,
305 false);
306
307 /* if search_argc == 0 (empty command line) shell_get_last_command will
308 * return NULL tab is allowed, otherwise not.
309 */
310 if ((*cmd == NULL) && (search_argc != 0)) {
311 return false;
312 }
313
314 return true;
315 }
316
is_completion_candidate(const char * candidate,const char * str,size_t len)317 static inline bool is_completion_candidate(const char *candidate,
318 const char *str, size_t len)
319 {
320 return (strncmp(candidate, str, len) == 0) ? true : false;
321 }
322
find_completion_candidates(const struct shell * sh,const struct shell_static_entry * cmd,const char * incompl_cmd,size_t * first_idx,size_t * cnt,uint16_t * longest)323 static void find_completion_candidates(const struct shell *sh,
324 const struct shell_static_entry *cmd,
325 const char *incompl_cmd,
326 size_t *first_idx, size_t *cnt,
327 uint16_t *longest)
328 {
329 const struct shell_static_entry *candidate;
330 struct shell_static_entry dloc;
331 size_t incompl_cmd_len;
332 size_t idx = 0;
333
334 incompl_cmd_len = z_shell_strlen(incompl_cmd);
335 *longest = 0U;
336 *cnt = 0;
337
338 while ((candidate = z_shell_cmd_get(cmd, idx, &dloc)) != NULL) {
339 bool is_candidate;
340 is_candidate = is_completion_candidate(candidate->syntax,
341 incompl_cmd, incompl_cmd_len);
342 if (is_candidate) {
343 *longest = Z_MAX(strlen(candidate->syntax), *longest);
344 if (*cnt == 0) {
345 *first_idx = idx;
346 }
347 (*cnt)++;
348 }
349
350 idx++;
351 }
352 }
353
autocomplete(const struct shell * sh,const struct shell_static_entry * cmd,const char * arg,size_t subcmd_idx)354 static void autocomplete(const struct shell *sh,
355 const struct shell_static_entry *cmd,
356 const char *arg,
357 size_t subcmd_idx)
358 {
359 const struct shell_static_entry *match;
360 uint16_t cmd_len;
361 uint16_t arg_len = z_shell_strlen(arg);
362
363 /* sh->ctx->active_cmd can be safely used outside of command context
364 * to save stack
365 */
366 match = z_shell_cmd_get(cmd, subcmd_idx, &sh->ctx->active_cmd);
367 __ASSERT_NO_MSG(match != NULL);
368 cmd_len = z_shell_strlen(match->syntax);
369
370 if (!IS_ENABLED(CONFIG_SHELL_TAB_AUTOCOMPLETION)) {
371 /* Add a space if the Tab button is pressed when command is
372 * complete.
373 */
374 if (cmd_len == arg_len) {
375 z_shell_op_char_insert(sh, ' ');
376 }
377 return;
378 }
379
380 /* no exact match found */
381 if (cmd_len != arg_len) {
382 z_shell_op_completion_insert(sh,
383 match->syntax + arg_len,
384 cmd_len - arg_len);
385 }
386
387 /* Next character in the buffer is not 'space'. */
388 if (isspace((int) sh->ctx->cmd_buff[
389 sh->ctx->cmd_buff_pos]) == 0) {
390 if (z_flag_insert_mode_get(sh)) {
391 z_flag_insert_mode_set(sh, false);
392 z_shell_op_char_insert(sh, ' ');
393 z_flag_insert_mode_set(sh, true);
394 } else {
395 z_shell_op_char_insert(sh, ' ');
396 }
397 } else {
398 /* case:
399 * | | -> cursor
400 * cons_name $: valid_cmd valid_sub_cmd| |argument <tab>
401 */
402 z_shell_op_cursor_move(sh, 1);
403 /* result:
404 * cons_name $: valid_cmd valid_sub_cmd |a|rgument
405 */
406 }
407 }
408
str_common(const char * s1,const char * s2,size_t n)409 static size_t str_common(const char *s1, const char *s2, size_t n)
410 {
411 size_t common = 0;
412
413 while ((n > 0) && (*s1 == *s2) && (*s1 != '\0')) {
414 s1++;
415 s2++;
416 n--;
417 common++;
418 }
419
420 return common;
421 }
422
tab_options_print(const struct shell * sh,const struct shell_static_entry * cmd,const char * str,size_t first,size_t cnt,uint16_t longest)423 static void tab_options_print(const struct shell *sh,
424 const struct shell_static_entry *cmd,
425 const char *str, size_t first, size_t cnt,
426 uint16_t longest)
427 {
428 const struct shell_static_entry *match;
429 size_t str_len = z_shell_strlen(str);
430 size_t idx = first;
431
432 /* Printing all matching commands (options). */
433 tab_item_print(sh, SHELL_INIT_OPTION_PRINTER, longest);
434
435 while (cnt) {
436 /* sh->ctx->active_cmd can be safely used outside of command
437 * context to save stack
438 */
439 match = z_shell_cmd_get(cmd, idx, &sh->ctx->active_cmd);
440 __ASSERT_NO_MSG(match != NULL);
441 idx++;
442 if (str && match->syntax &&
443 !is_completion_candidate(match->syntax, str, str_len)) {
444 continue;
445 }
446
447 tab_item_print(sh, match->syntax, longest);
448 cnt--;
449 }
450
451 z_cursor_next_line_move(sh);
452 z_shell_print_prompt_and_cmd(sh);
453 }
454
common_beginning_find(const struct shell * sh,const struct shell_static_entry * cmd,const char ** str,size_t first,size_t cnt,uint16_t arg_len)455 static uint16_t common_beginning_find(const struct shell *sh,
456 const struct shell_static_entry *cmd,
457 const char **str,
458 size_t first, size_t cnt, uint16_t arg_len)
459 {
460 struct shell_static_entry dynamic_entry;
461 const struct shell_static_entry *match;
462 uint16_t common = UINT16_MAX;
463 size_t idx = first + 1;
464
465 __ASSERT_NO_MSG(cnt > 1);
466
467 match = z_shell_cmd_get(cmd, first, &dynamic_entry);
468 __ASSERT_NO_MSG(match);
469 strncpy(sh->ctx->temp_buff, match->syntax,
470 sizeof(sh->ctx->temp_buff) - 1);
471
472 *str = match->syntax;
473
474 while (cnt > 1) {
475 struct shell_static_entry dynamic_entry2;
476 const struct shell_static_entry *match2;
477 int curr_common;
478
479 match2 = z_shell_cmd_get(cmd, idx++, &dynamic_entry2);
480 if (match2 == NULL) {
481 break;
482 }
483
484 curr_common = str_common(sh->ctx->temp_buff, match2->syntax,
485 UINT16_MAX);
486 if ((arg_len == 0U) || (curr_common >= arg_len)) {
487 --cnt;
488 common = (curr_common < common) ? curr_common : common;
489 }
490 }
491
492 return common;
493 }
494
partial_autocomplete(const struct shell * sh,const struct shell_static_entry * cmd,const char * arg,size_t first,size_t cnt)495 static void partial_autocomplete(const struct shell *sh,
496 const struct shell_static_entry *cmd,
497 const char *arg,
498 size_t first, size_t cnt)
499 {
500 const char *completion;
501 uint16_t arg_len = z_shell_strlen(arg);
502 uint16_t common = common_beginning_find(sh, cmd, &completion, first,
503 cnt, arg_len);
504
505 if (!IS_ENABLED(CONFIG_SHELL_TAB_AUTOCOMPLETION)) {
506 return;
507 }
508
509 if (common) {
510 z_shell_op_completion_insert(sh, &completion[arg_len],
511 common - arg_len);
512 }
513 }
514
exec_cmd(const struct shell * sh,size_t argc,const char ** argv,const struct shell_static_entry * help_entry)515 static int exec_cmd(const struct shell *sh, size_t argc, const char **argv,
516 const struct shell_static_entry *help_entry)
517 {
518 int ret_val = 0;
519
520 if (sh->ctx->active_cmd.handler == NULL) {
521 if ((help_entry != NULL) && IS_ENABLED(CONFIG_SHELL_HELP)) {
522 if (help_entry->help == NULL) {
523 return -ENOEXEC;
524 }
525 if (help_entry->help != sh->ctx->active_cmd.help) {
526 sh->ctx->active_cmd = *help_entry;
527 }
528 shell_internal_help_print(sh);
529 return SHELL_CMD_HELP_PRINTED;
530 } else {
531 if (IS_ENABLED(CONFIG_SHELL_MSG_SPECIFY_SUBCOMMAND)) {
532 z_shell_fprintf(sh, SHELL_ERROR,
533 SHELL_MSG_SPECIFY_SUBCOMMAND);
534 }
535 return -ENOEXEC;
536 }
537 }
538
539 if (sh->ctx->active_cmd.args.mandatory) {
540 uint32_t mand = sh->ctx->active_cmd.args.mandatory;
541 uint8_t opt8 = sh->ctx->active_cmd.args.optional;
542 uint32_t opt = (opt8 == SHELL_OPT_ARG_CHECK_SKIP) ?
543 UINT16_MAX : opt8;
544 const bool in_range = IN_RANGE(argc, mand, mand + opt);
545
546 /* Check if argc is within allowed range */
547 ret_val = cmd_precheck(sh, in_range);
548 }
549
550 if (!ret_val) {
551 #if CONFIG_SHELL_GETOPT
552 getopt_init();
553 #endif
554
555 z_flag_cmd_ctx_set(sh, true);
556 /* Unlock thread mutex in case command would like to borrow
557 * shell context to other thread to avoid mutex deadlock.
558 */
559 k_mutex_unlock(&sh->ctx->wr_mtx);
560 ret_val = sh->ctx->active_cmd.handler(sh, argc,
561 (char **)argv);
562 /* Bring back mutex to shell thread. */
563 k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER);
564 z_flag_cmd_ctx_set(sh, false);
565 }
566
567 return ret_val;
568 }
569
active_cmd_prepare(const struct shell_static_entry * entry,struct shell_static_entry * active_cmd,struct shell_static_entry * help_entry,size_t * lvl,size_t * handler_lvl,size_t * args_left)570 static void active_cmd_prepare(const struct shell_static_entry *entry,
571 struct shell_static_entry *active_cmd,
572 struct shell_static_entry *help_entry,
573 size_t *lvl, size_t *handler_lvl,
574 size_t *args_left)
575 {
576 if (entry->handler) {
577 *handler_lvl = *lvl;
578 *active_cmd = *entry;
579 /* If command is final handler and it has a raw optional argument,
580 * then set remaining arguments to mandatory - 1 so after processing mandatory
581 * args, handler is passed remaining raw string
582 */
583 if ((entry->subcmd == NULL)
584 && entry->args.optional == SHELL_OPT_ARG_RAW) {
585 *args_left = entry->args.mandatory - 1;
586 }
587 }
588 if (entry->help) {
589 *help_entry = *entry;
590 }
591 }
592
wildcard_check_report(const struct shell * sh,bool found,const struct shell_static_entry * entry)593 static bool wildcard_check_report(const struct shell *sh, bool found,
594 const struct shell_static_entry *entry)
595 {
596 /* An error occurred, fnmatch argument cannot be followed by argument
597 * with a handler to avoid multiple function calls.
598 */
599 if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && found && entry->handler) {
600 z_shell_op_cursor_end_move(sh);
601 z_shell_op_cond_next_line(sh);
602
603 z_shell_fprintf(sh, SHELL_ERROR,
604 "Error: requested multiple function executions\n");
605 return false;
606 }
607
608 return true;
609 }
610
611 /* Function is analyzing the command buffer to find matching commands. Next, it
612 * invokes the last recognized command which has a handler and passes the rest
613 * of command buffer as arguments.
614 *
615 * By default command buffer is parsed and spaces are treated by arguments
616 * separators. Complex arguments are provided in quotation marks with quotation
617 * marks escaped within the argument. Argument parser is removing quotation
618 * marks at argument boundary as well as escape characters within the argument.
619 * However, it is possible to indicate that command shall treat remaining part
620 * of command buffer as the last argument without parsing. This can be used for
621 * commands which expects whole command buffer to be passed directly to
622 * the command handler without any preprocessing.
623 * Because of that feature, command buffer is processed argument by argument and
624 * decision on further processing is based on currently processed command.
625 */
execute(const struct shell * sh)626 static int execute(const struct shell *sh)
627 {
628 struct shell_static_entry dloc; /* Memory for dynamic commands. */
629 const char *argv[CONFIG_SHELL_ARGC_MAX + 1] = {0}; /* +1 reserved for NULL */
630 const struct shell_static_entry *parent = selected_cmd_get(sh);
631 const struct shell_static_entry *entry = NULL;
632 struct shell_static_entry help_entry;
633 size_t cmd_lvl = 0;
634 size_t cmd_with_handler_lvl = 0;
635 bool wildcard_found = false;
636 size_t argc = 0, args_left = SIZE_MAX;
637 char quote;
638 const char **argvp;
639 char *cmd_buf = sh->ctx->cmd_buff;
640 bool has_last_handler = false;
641
642 z_shell_op_cursor_end_move(sh);
643 if (!z_shell_cursor_in_empty_line(sh)) {
644 z_cursor_next_line_move(sh);
645 }
646
647 memset(&sh->ctx->active_cmd, 0, sizeof(sh->ctx->active_cmd));
648
649 if (IS_ENABLED(CONFIG_SHELL_HISTORY)) {
650 z_shell_cmd_trim(sh);
651 history_put(sh, sh->ctx->cmd_buff,
652 sh->ctx->cmd_buff_len);
653 }
654
655 if (IS_ENABLED(CONFIG_SHELL_WILDCARD)) {
656 z_shell_wildcard_prepare(sh);
657 }
658
659 /* Parent present means we are in select mode. */
660 if (parent != NULL) {
661 argv[0] = parent->syntax;
662 argv[1] = cmd_buf;
663 argvp = &argv[1];
664 active_cmd_prepare(parent, &sh->ctx->active_cmd, &help_entry,
665 &cmd_lvl, &cmd_with_handler_lvl, &args_left);
666 cmd_lvl++;
667 } else {
668 help_entry.help = NULL;
669 argvp = &argv[0];
670 }
671
672 /* Below loop is analyzing subcommands of found root command. */
673 while ((argc != 1) && (cmd_lvl < CONFIG_SHELL_ARGC_MAX)
674 && args_left > 0) {
675 quote = z_shell_make_argv(&argc, argvp, cmd_buf, 2);
676 cmd_buf = (char *)argvp[1];
677
678 if (argc == 0) {
679 return -ENOEXEC;
680 } else if ((argc == 1) && (quote != 0)) {
681 z_shell_fprintf(sh, SHELL_ERROR,
682 "not terminated: %c\n", quote);
683 return -ENOEXEC;
684 }
685
686 if (IS_ENABLED(CONFIG_SHELL_HELP) && (cmd_lvl > 0) &&
687 z_shell_help_request(argvp[0])) {
688 /* Command called with help option so it makes no sense
689 * to search deeper commands.
690 */
691 if (help_entry.help) {
692 sh->ctx->active_cmd = help_entry;
693 shell_internal_help_print(sh);
694 return SHELL_CMD_HELP_PRINTED;
695 }
696
697 if (IS_ENABLED(CONFIG_SHELL_MSG_SPECIFY_SUBCOMMAND)) {
698 z_shell_fprintf(sh, SHELL_ERROR,
699 SHELL_MSG_SPECIFY_SUBCOMMAND);
700 }
701 return -ENOEXEC;
702 }
703
704 if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && (cmd_lvl > 0)) {
705 enum shell_wildcard_status status;
706
707 status = z_shell_wildcard_process(sh, entry,
708 argvp[0]);
709 /* Wildcard character found but there is no matching
710 * command.
711 */
712 if (status == SHELL_WILDCARD_CMD_NO_MATCH_FOUND) {
713 break;
714 }
715
716 /* Wildcard character was not found function can process
717 * argument.
718 */
719 if (status != SHELL_WILDCARD_NOT_FOUND) {
720 ++cmd_lvl;
721 wildcard_found = true;
722 continue;
723 }
724 }
725
726 if (has_last_handler == false) {
727 entry = z_shell_find_cmd(parent, argvp[0], &dloc);
728 }
729
730 argvp++;
731 args_left--;
732 if (entry) {
733 if (wildcard_check_report(sh, wildcard_found, entry)
734 == false) {
735 return -ENOEXEC;
736 }
737
738 active_cmd_prepare(entry, &sh->ctx->active_cmd,
739 &help_entry, &cmd_lvl,
740 &cmd_with_handler_lvl, &args_left);
741 parent = entry;
742 } else {
743 if (IS_ENABLED(CONFIG_SHELL_MSG_CMD_NOT_FOUND) &&
744 cmd_lvl == 0 &&
745 (!z_shell_in_select_mode(sh) ||
746 sh->ctx->selected_cmd->handler == NULL)) {
747 z_shell_fprintf(sh, SHELL_ERROR,
748 "%s%s\n", argv[0],
749 SHELL_MSG_CMD_NOT_FOUND);
750 }
751
752 /* last handler found - no need to search commands in
753 * the next iteration.
754 */
755 has_last_handler = true;
756 }
757
758 if (args_left || (argc == 2)) {
759 cmd_lvl++;
760 }
761
762 }
763
764 if ((cmd_lvl >= CONFIG_SHELL_ARGC_MAX) && (argc == 2)) {
765 /* argc == 2 indicates that when command string was parsed
766 * there was more characters remaining. It means that number of
767 * arguments exceeds the limit.
768 */
769 z_shell_fprintf(sh, SHELL_ERROR, "%s\n",
770 SHELL_MSG_TOO_MANY_ARGS);
771 return -ENOEXEC;
772 }
773
774 if (IS_ENABLED(CONFIG_SHELL_WILDCARD) && wildcard_found) {
775 z_shell_wildcard_finalize(sh);
776 /* cmd_buffer has been overwritten by function finalize function
777 * with all expanded commands. Hence shell_make_argv needs to
778 * be called again.
779 */
780 (void)z_shell_make_argv(&cmd_lvl,
781 &argv[selected_cmd_get(sh) ? 1 : 0],
782 sh->ctx->cmd_buff,
783 CONFIG_SHELL_ARGC_MAX);
784
785 if (selected_cmd_get(sh)) {
786 /* Apart from what is in the command buffer, there is
787 * a selected command.
788 */
789 cmd_lvl++;
790 }
791 }
792
793 /* If a command was found */
794 if (parent != NULL) {
795 /* If the found command uses a raw optional argument and
796 * we have a remaining unprocessed non-null string,
797 * then increment command level so handler receives raw string
798 */
799 if (parent->args.optional == SHELL_OPT_ARG_RAW && argv[cmd_lvl] != NULL) {
800 cmd_lvl++;
801 }
802 }
803
804 /* Executing the deepest found handler. */
805 return exec_cmd(sh, cmd_lvl - cmd_with_handler_lvl,
806 &argv[cmd_with_handler_lvl], &help_entry);
807 }
808
tab_handle(const struct shell * sh)809 static void tab_handle(const struct shell *sh)
810 {
811 const char *__argv[CONFIG_SHELL_ARGC_MAX + 1];
812 /* d_entry - placeholder for dynamic command */
813 struct shell_static_entry d_entry;
814 const struct shell_static_entry *cmd;
815 const char **argv = __argv;
816 size_t first = 0;
817 size_t arg_idx;
818 uint16_t longest;
819 size_t argc;
820 size_t cnt;
821
822 bool tab_possible = tab_prepare(sh, &cmd, &argv, &argc, &arg_idx,
823 &d_entry);
824
825 if (tab_possible == false) {
826 return;
827 }
828
829 find_completion_candidates(sh, cmd, argv[arg_idx], &first, &cnt,
830 &longest);
831
832 if (cnt == 1) {
833 /* Autocompletion.*/
834 autocomplete(sh, cmd, argv[arg_idx], first);
835 } else if (cnt > 1) {
836 tab_options_print(sh, cmd, argv[arg_idx], first, cnt,
837 longest);
838 partial_autocomplete(sh, cmd, argv[arg_idx], first, cnt);
839 }
840 }
841
alt_metakeys_handle(const struct shell * sh,char data)842 static void alt_metakeys_handle(const struct shell *sh, char data)
843 {
844 /* Optional feature */
845 if (!IS_ENABLED(CONFIG_SHELL_METAKEYS)) {
846 return;
847 }
848 if (data == SHELL_VT100_ASCII_ALT_B) {
849 z_shell_op_cursor_word_move(sh, -1);
850 } else if (data == SHELL_VT100_ASCII_ALT_F) {
851 z_shell_op_cursor_word_move(sh, 1);
852 } else if (data == SHELL_VT100_ASCII_ALT_R &&
853 IS_ENABLED(CONFIG_SHELL_CMDS_SELECT)) {
854 if (selected_cmd_get(sh) != NULL) {
855 z_shell_cmd_line_erase(sh);
856 z_shell_fprintf(sh, SHELL_WARNING,
857 "Restored default root commands\n");
858 if (CONFIG_SHELL_CMD_ROOT[0]) {
859 sh->ctx->selected_cmd = root_cmd_find(CONFIG_SHELL_CMD_ROOT);
860 } else {
861 sh->ctx->selected_cmd = NULL;
862 }
863 z_shell_print_prompt_and_cmd(sh);
864 }
865 }
866 }
867
ctrl_metakeys_handle(const struct shell * sh,char data)868 static void ctrl_metakeys_handle(const struct shell *sh, char data)
869 {
870 /* Optional feature */
871 if (!IS_ENABLED(CONFIG_SHELL_METAKEYS)) {
872 return;
873 }
874
875 switch (data) {
876 case SHELL_VT100_ASCII_CTRL_A: /* CTRL + A */
877 z_shell_op_cursor_home_move(sh);
878 break;
879
880 case SHELL_VT100_ASCII_CTRL_B: /* CTRL + B */
881 z_shell_op_left_arrow(sh);
882 break;
883
884 case SHELL_VT100_ASCII_CTRL_C: /* CTRL + C */
885 z_shell_op_cursor_end_move(sh);
886 if (!z_shell_cursor_in_empty_line(sh)) {
887 z_cursor_next_line_move(sh);
888 }
889 z_flag_history_exit_set(sh, true);
890 state_set(sh, SHELL_STATE_ACTIVE);
891 break;
892
893 case SHELL_VT100_ASCII_CTRL_D: /* CTRL + D */
894 z_shell_op_char_delete(sh);
895 break;
896
897 case SHELL_VT100_ASCII_CTRL_E: /* CTRL + E */
898 z_shell_op_cursor_end_move(sh);
899 break;
900
901 case SHELL_VT100_ASCII_CTRL_F: /* CTRL + F */
902 z_shell_op_right_arrow(sh);
903 break;
904
905 case SHELL_VT100_ASCII_CTRL_K: /* CTRL + K */
906 z_shell_op_delete_from_cursor(sh);
907 break;
908
909 case SHELL_VT100_ASCII_CTRL_L: /* CTRL + L */
910 Z_SHELL_VT100_CMD(sh, SHELL_VT100_CURSORHOME);
911 Z_SHELL_VT100_CMD(sh, SHELL_VT100_CLEARSCREEN);
912 z_shell_print_prompt_and_cmd(sh);
913 break;
914
915 case SHELL_VT100_ASCII_CTRL_N: /* CTRL + N */
916 history_handle(sh, false);
917 break;
918
919 case SHELL_VT100_ASCII_CTRL_P: /* CTRL + P */
920 history_handle(sh, true);
921 break;
922
923 case SHELL_VT100_ASCII_CTRL_U: /* CTRL + U */
924 z_shell_op_cursor_home_move(sh);
925 cmd_buffer_clear(sh);
926 z_flag_history_exit_set(sh, true);
927 z_clear_eos(sh);
928 break;
929
930 case SHELL_VT100_ASCII_CTRL_W: /* CTRL + W */
931 z_shell_op_word_remove(sh);
932 z_flag_history_exit_set(sh, true);
933 break;
934
935 default:
936 break;
937 }
938 }
939
940 /* Functions returns true if new line character shall be processed */
process_nl(const struct shell * sh,uint8_t data)941 static bool process_nl(const struct shell *sh, uint8_t data)
942 {
943 if ((data != '\r') && (data != '\n')) {
944 z_flag_last_nl_set(sh, 0);
945 return false;
946 }
947
948 if ((z_flag_last_nl_get(sh) == 0U) ||
949 (data == z_flag_last_nl_get(sh))) {
950 z_flag_last_nl_set(sh, data);
951 return true;
952 }
953
954 return false;
955 }
956
957 #define SHELL_ASCII_MAX_CHAR (127u)
ascii_filter(const char data)958 static inline int ascii_filter(const char data)
959 {
960 if (IS_ENABLED(CONFIG_SHELL_ASCII_FILTER)) {
961 return (uint8_t) data > SHELL_ASCII_MAX_CHAR ? -EINVAL : 0;
962 } else {
963 return 0;
964 }
965 }
966
state_collect(const struct shell * sh)967 static void state_collect(const struct shell *sh)
968 {
969 size_t count = 0;
970 char data;
971
972 while (true) {
973 shell_bypass_cb_t bypass = sh->ctx->bypass;
974
975 if (bypass) {
976 uint8_t buf[16];
977
978 (void)sh->iface->api->read(sh->iface, buf,
979 sizeof(buf), &count);
980 if (count) {
981 z_flag_cmd_ctx_set(sh, true);
982 bypass(sh, buf, count);
983 z_flag_cmd_ctx_set(sh, false);
984 /* Check if bypass mode ended. */
985 if (!(volatile shell_bypass_cb_t *)sh->ctx->bypass) {
986 state_set(sh, SHELL_STATE_ACTIVE);
987 } else {
988 continue;
989 }
990 }
991
992 return;
993 }
994
995 (void)sh->iface->api->read(sh->iface, &data,
996 sizeof(data), &count);
997 if (count == 0) {
998 return;
999 }
1000
1001 if (ascii_filter(data) != 0) {
1002 continue;
1003 }
1004
1005 switch (sh->ctx->receive_state) {
1006 case SHELL_RECEIVE_DEFAULT:
1007 if (process_nl(sh, data)) {
1008 if (!sh->ctx->cmd_buff_len) {
1009 history_mode_exit(sh);
1010 z_cursor_next_line_move(sh);
1011 } else {
1012 /* Command execution */
1013 sh->ctx->ret_val = execute(sh);
1014 }
1015 /* Function responsible for printing prompt
1016 * on received NL.
1017 */
1018 state_set(sh, SHELL_STATE_ACTIVE);
1019 continue;
1020 }
1021
1022 switch (data) {
1023 case SHELL_VT100_ASCII_ESC: /* ESCAPE */
1024 receive_state_change(sh, SHELL_RECEIVE_ESC);
1025 break;
1026
1027 case '\0':
1028 break;
1029
1030 case '\t': /* TAB */
1031 if (z_flag_echo_get(sh) &&
1032 IS_ENABLED(CONFIG_SHELL_TAB)) {
1033 /* If the Tab key is pressed, "history
1034 * mode" must be terminated because
1035 * tab and history handlers are sharing
1036 * the same array: temp_buff.
1037 */
1038 z_flag_history_exit_set(sh, true);
1039 tab_handle(sh);
1040 }
1041 break;
1042
1043 case SHELL_VT100_ASCII_BSPACE: /* BACKSPACE */
1044 if (z_flag_echo_get(sh)) {
1045 z_flag_history_exit_set(sh, true);
1046 z_shell_op_char_backspace(sh);
1047 }
1048 break;
1049
1050 case SHELL_VT100_ASCII_DEL: /* DELETE */
1051 if (z_flag_echo_get(sh)) {
1052 z_flag_history_exit_set(sh, true);
1053 if (z_flag_mode_delete_get(sh)) {
1054 z_shell_op_char_backspace(sh);
1055
1056 } else {
1057 z_shell_op_char_delete(sh);
1058 }
1059 }
1060 break;
1061
1062 default:
1063 if (isprint((int) data) != 0) {
1064 z_flag_history_exit_set(sh, true);
1065 z_shell_op_char_insert(sh, data);
1066 } else if (z_flag_echo_get(sh)) {
1067 ctrl_metakeys_handle(sh, data);
1068 }
1069 break;
1070 }
1071 break;
1072
1073 case SHELL_RECEIVE_ESC:
1074 if (data == '[') {
1075 receive_state_change(sh,
1076 SHELL_RECEIVE_ESC_SEQ);
1077 break;
1078 } else if (z_flag_echo_get(sh)) {
1079 alt_metakeys_handle(sh, data);
1080 }
1081 receive_state_change(sh, SHELL_RECEIVE_DEFAULT);
1082 break;
1083
1084 case SHELL_RECEIVE_ESC_SEQ:
1085 receive_state_change(sh, SHELL_RECEIVE_DEFAULT);
1086
1087 if (!z_flag_echo_get(sh)) {
1088 continue;
1089 }
1090
1091 switch (data) {
1092 case 'A': /* UP arrow */
1093 history_handle(sh, true);
1094 break;
1095
1096 case 'B': /* DOWN arrow */
1097 history_handle(sh, false);
1098 break;
1099
1100 case 'C': /* RIGHT arrow */
1101 z_shell_op_right_arrow(sh);
1102 break;
1103
1104 case 'D': /* LEFT arrow */
1105 z_shell_op_left_arrow(sh);
1106 break;
1107
1108 case '4': /* END Button in ESC[n~ mode */
1109 receive_state_change(sh,
1110 SHELL_RECEIVE_TILDE_EXP);
1111 __fallthrough;
1112 case 'F': /* END Button in VT100 mode */
1113 z_shell_op_cursor_end_move(sh);
1114 break;
1115
1116 case '1': /* HOME Button in ESC[n~ mode */
1117 receive_state_change(sh,
1118 SHELL_RECEIVE_TILDE_EXP);
1119 __fallthrough;
1120 case 'H': /* HOME Button in VT100 mode */
1121 z_shell_op_cursor_home_move(sh);
1122 break;
1123
1124 case '2': /* INSERT Button in ESC[n~ mode */
1125 receive_state_change(sh,
1126 SHELL_RECEIVE_TILDE_EXP);
1127 __fallthrough;
1128 case 'L': {/* INSERT Button in VT100 mode */
1129 bool status = z_flag_insert_mode_get(sh);
1130
1131 z_flag_insert_mode_set(sh, !status);
1132 break;
1133 }
1134
1135 case '3':/* DELETE Button in ESC[n~ mode */
1136 receive_state_change(sh,
1137 SHELL_RECEIVE_TILDE_EXP);
1138 if (z_flag_echo_get(sh)) {
1139 z_shell_op_char_delete(sh);
1140 }
1141 break;
1142
1143 default:
1144 break;
1145 }
1146 break;
1147
1148 case SHELL_RECEIVE_TILDE_EXP:
1149 receive_state_change(sh, SHELL_RECEIVE_DEFAULT);
1150 break;
1151
1152 default:
1153 receive_state_change(sh, SHELL_RECEIVE_DEFAULT);
1154 break;
1155 }
1156 }
1157
1158 z_transport_buffer_flush(sh);
1159 }
1160
transport_evt_handler(enum shell_transport_evt evt_type,void * ctx)1161 static void transport_evt_handler(enum shell_transport_evt evt_type, void *ctx)
1162 {
1163 struct shell *sh = (struct shell *)ctx;
1164 struct k_poll_signal *signal;
1165
1166 signal = (evt_type == SHELL_TRANSPORT_EVT_RX_RDY) ?
1167 &sh->ctx->signals[SHELL_SIGNAL_RXRDY] :
1168 &sh->ctx->signals[SHELL_SIGNAL_TXDONE];
1169 k_poll_signal_raise(signal, 0);
1170 }
1171
shell_log_process(const struct shell * sh)1172 static void shell_log_process(const struct shell *sh)
1173 {
1174 bool processed = false;
1175 int signaled = 0;
1176 int result;
1177
1178 do {
1179 if (!IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE)) {
1180 z_shell_cmd_line_erase(sh);
1181
1182 processed = z_shell_log_backend_process(
1183 sh->log_backend);
1184 }
1185
1186 struct k_poll_signal *signal =
1187 &sh->ctx->signals[SHELL_SIGNAL_RXRDY];
1188
1189 z_shell_print_prompt_and_cmd(sh);
1190
1191 /* Arbitrary delay added to ensure that prompt is
1192 * readable and can be used to enter further commands.
1193 */
1194 if (sh->ctx->cmd_buff_len) {
1195 k_sleep(K_MSEC(15));
1196 }
1197
1198 k_poll_signal_check(signal, &signaled, &result);
1199
1200 } while (processed && !signaled);
1201 }
1202
instance_init(const struct shell * sh,const void * transport_config,struct shell_backend_config_flags cfg_flags)1203 static int instance_init(const struct shell *sh,
1204 const void *transport_config,
1205 struct shell_backend_config_flags cfg_flags)
1206 {
1207 __ASSERT_NO_MSG((sh->shell_flag == SHELL_FLAG_CRLF_DEFAULT) ||
1208 (sh->shell_flag == SHELL_FLAG_OLF_CRLF));
1209
1210 memset(sh->ctx, 0, sizeof(*sh->ctx));
1211 if (CONFIG_SHELL_CMD_ROOT[0]) {
1212 sh->ctx->selected_cmd = root_cmd_find(CONFIG_SHELL_CMD_ROOT);
1213 }
1214
1215 history_init(sh);
1216
1217 k_mutex_init(&sh->ctx->wr_mtx);
1218
1219 for (int i = 0; i < SHELL_SIGNALS; i++) {
1220 k_poll_signal_init(&sh->ctx->signals[i]);
1221 k_poll_event_init(&sh->ctx->events[i],
1222 K_POLL_TYPE_SIGNAL,
1223 K_POLL_MODE_NOTIFY_ONLY,
1224 &sh->ctx->signals[i]);
1225 }
1226
1227 if (IS_ENABLED(CONFIG_SHELL_STATS)) {
1228 sh->stats->log_lost_cnt = 0;
1229 }
1230
1231 z_flag_tx_rdy_set(sh, true);
1232
1233 sh->ctx->vt100_ctx.cons.terminal_wid =
1234 CONFIG_SHELL_DEFAULT_TERMINAL_WIDTH;
1235 sh->ctx->vt100_ctx.cons.terminal_hei =
1236 CONFIG_SHELL_DEFAULT_TERMINAL_HEIGHT;
1237
1238 #if defined(CONFIG_SHELL_PROMPT_CHANGE) && CONFIG_SHELL_PROMPT_CHANGE
1239 shell_prompt_change(sh, sh->default_prompt);
1240 #else
1241 sh->ctx->prompt = sh->default_prompt;
1242 sh->ctx->vt100_ctx.cons.name_len = z_shell_strlen(sh->ctx->prompt);
1243 #endif
1244
1245 /* Configure backend according to enabled shell features and backend
1246 * specific settings.
1247 */
1248 cfg_flags.obscure &= IS_ENABLED(CONFIG_SHELL_START_OBSCURED);
1249 cfg_flags.use_colors &= IS_ENABLED(CONFIG_SHELL_VT100_COLORS);
1250 cfg_flags.use_vt100 &= IS_ENABLED(CONFIG_SHELL_VT100_COMMANDS);
1251 cfg_flags.echo &= IS_ENABLED(CONFIG_SHELL_ECHO_STATUS);
1252 cfg_flags.mode_delete &= IS_ENABLED(CONFIG_SHELL_BACKSPACE_MODE_DELETE);
1253 sh->ctx->cfg.flags = cfg_flags;
1254
1255 int ret = sh->iface->api->init(sh->iface, transport_config,
1256 transport_evt_handler,
1257 (void *)sh);
1258 if (ret == 0) {
1259 state_set(sh, SHELL_STATE_INITIALIZED);
1260 }
1261
1262 return ret;
1263 }
1264
instance_uninit(const struct shell * sh)1265 static int instance_uninit(const struct shell *sh)
1266 {
1267 __ASSERT_NO_MSG(sh);
1268 __ASSERT_NO_MSG(sh->ctx && sh->iface);
1269
1270 int err;
1271
1272 if (z_flag_processing_get(sh)) {
1273 return -EBUSY;
1274 }
1275
1276 if (IS_ENABLED(CONFIG_SHELL_LOG_BACKEND)) {
1277 /* todo purge log queue */
1278 z_shell_log_backend_disable(sh->log_backend);
1279 }
1280
1281 err = sh->iface->api->uninit(sh->iface);
1282 if (err != 0) {
1283 return err;
1284 }
1285
1286 history_purge(sh);
1287 state_set(sh, SHELL_STATE_UNINITIALIZED);
1288
1289 return 0;
1290 }
1291
1292 typedef void (*shell_signal_handler_t)(const struct shell *sh);
1293
shell_signal_handle(const struct shell * sh,enum shell_signal sig_idx,shell_signal_handler_t handler)1294 static void shell_signal_handle(const struct shell *sh,
1295 enum shell_signal sig_idx,
1296 shell_signal_handler_t handler)
1297 {
1298 struct k_poll_signal *sig = &sh->ctx->signals[sig_idx];
1299 int set;
1300 int res;
1301
1302 k_poll_signal_check(sig, &set, &res);
1303
1304 if (set) {
1305 k_poll_signal_reset(sig);
1306 handler(sh);
1307 }
1308 }
1309
kill_handler(const struct shell * sh)1310 static void kill_handler(const struct shell *sh)
1311 {
1312 int err = instance_uninit(sh);
1313
1314 if (sh->ctx->uninit_cb) {
1315 sh->ctx->uninit_cb(sh, err);
1316 }
1317
1318 sh->ctx->tid = NULL;
1319 k_thread_abort(k_current_get());
1320
1321 CODE_UNREACHABLE;
1322 }
1323
shell_thread(void * shell_handle,void * arg_log_backend,void * arg_log_level)1324 void shell_thread(void *shell_handle, void *arg_log_backend,
1325 void *arg_log_level)
1326 {
1327 struct shell *sh = shell_handle;
1328 int err;
1329
1330 z_flag_handle_log_set(sh, (bool)arg_log_backend);
1331 sh->ctx->log_level = POINTER_TO_UINT(arg_log_level);
1332
1333 err = sh->iface->api->enable(sh->iface, false);
1334 if (err != 0) {
1335 return;
1336 }
1337
1338 if (IS_ENABLED(CONFIG_SHELL_AUTOSTART)) {
1339 /* Enable shell and print prompt. */
1340 err = shell_start(sh);
1341 if (err != 0) {
1342 return;
1343 }
1344 }
1345
1346 while (true) {
1347 /* waiting for all signals except SHELL_SIGNAL_TXDONE */
1348 err = k_poll(sh->ctx->events, SHELL_SIGNAL_TXDONE,
1349 K_FOREVER);
1350
1351 if (err != 0) {
1352 k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER);
1353 z_shell_fprintf(sh, SHELL_ERROR,
1354 "Shell thread error: %d", err);
1355 k_mutex_unlock(&sh->ctx->wr_mtx);
1356 return;
1357 }
1358
1359 k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER);
1360
1361 shell_signal_handle(sh, SHELL_SIGNAL_KILL, kill_handler);
1362 shell_signal_handle(sh, SHELL_SIGNAL_RXRDY, shell_process);
1363 if (IS_ENABLED(CONFIG_SHELL_LOG_BACKEND)) {
1364 shell_signal_handle(sh, SHELL_SIGNAL_LOG_MSG,
1365 shell_log_process);
1366 }
1367
1368 if (sh->iface->api->update) {
1369 sh->iface->api->update(sh->iface);
1370 }
1371
1372 k_mutex_unlock(&sh->ctx->wr_mtx);
1373 }
1374 }
1375
shell_init(const struct shell * sh,const void * transport_config,struct shell_backend_config_flags cfg_flags,bool log_backend,uint32_t init_log_level)1376 int shell_init(const struct shell *sh, const void *transport_config,
1377 struct shell_backend_config_flags cfg_flags,
1378 bool log_backend, uint32_t init_log_level)
1379 {
1380 __ASSERT_NO_MSG(sh);
1381 __ASSERT_NO_MSG(sh->ctx && sh->iface && sh->default_prompt);
1382
1383 if (sh->ctx->tid) {
1384 return -EALREADY;
1385 }
1386
1387 int err = instance_init(sh, transport_config, cfg_flags);
1388
1389 if (err != 0) {
1390 return err;
1391 }
1392
1393 k_tid_t tid = k_thread_create(sh->thread,
1394 sh->stack, CONFIG_SHELL_STACK_SIZE,
1395 shell_thread, (void *)sh, (void *)log_backend,
1396 UINT_TO_POINTER(init_log_level),
1397 SHELL_THREAD_PRIORITY, 0, K_NO_WAIT);
1398
1399 sh->ctx->tid = tid;
1400 k_thread_name_set(tid, sh->name);
1401
1402 return 0;
1403 }
1404
shell_uninit(const struct shell * sh,shell_uninit_cb_t cb)1405 void shell_uninit(const struct shell *sh, shell_uninit_cb_t cb)
1406 {
1407 __ASSERT_NO_MSG(sh);
1408
1409 if (IS_ENABLED(CONFIG_MULTITHREADING)) {
1410 struct k_poll_signal *signal =
1411 &sh->ctx->signals[SHELL_SIGNAL_KILL];
1412
1413 sh->ctx->uninit_cb = cb;
1414 /* signal kill message */
1415 (void)k_poll_signal_raise(signal, 0);
1416
1417 return;
1418 }
1419
1420 int err = instance_uninit(sh);
1421
1422 if (cb) {
1423 cb(sh, err);
1424 } else {
1425 __ASSERT_NO_MSG(0);
1426 }
1427 }
1428
shell_start(const struct shell * sh)1429 int shell_start(const struct shell *sh)
1430 {
1431 __ASSERT_NO_MSG(sh);
1432 __ASSERT_NO_MSG(sh->ctx && sh->iface && sh->default_prompt);
1433
1434 if (state_get(sh) != SHELL_STATE_INITIALIZED) {
1435 return -ENOTSUP;
1436 }
1437
1438 if (IS_ENABLED(CONFIG_SHELL_LOG_BACKEND) && z_flag_handle_log_get(sh)
1439 && !z_flag_obscure_get(sh)) {
1440 z_shell_log_backend_enable(sh->log_backend, (void *)sh, sh->ctx->log_level);
1441 }
1442
1443 k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER);
1444
1445 if (IS_ENABLED(CONFIG_SHELL_VT100_COLORS)) {
1446 z_shell_vt100_color_set(sh, SHELL_NORMAL);
1447 }
1448
1449 if (z_shell_strlen(sh->default_prompt) > 0) {
1450 z_shell_raw_fprintf(sh->fprintf_ctx, "\n\n");
1451 }
1452 state_set(sh, SHELL_STATE_ACTIVE);
1453
1454 k_mutex_unlock(&sh->ctx->wr_mtx);
1455
1456 return 0;
1457 }
1458
shell_stop(const struct shell * sh)1459 int shell_stop(const struct shell *sh)
1460 {
1461 __ASSERT_NO_MSG(sh);
1462 __ASSERT_NO_MSG(sh->ctx);
1463
1464 enum shell_state state = state_get(sh);
1465
1466 if ((state == SHELL_STATE_INITIALIZED) ||
1467 (state == SHELL_STATE_UNINITIALIZED)) {
1468 return -ENOTSUP;
1469 }
1470
1471 state_set(sh, SHELL_STATE_INITIALIZED);
1472
1473 if (IS_ENABLED(CONFIG_SHELL_LOG_BACKEND)) {
1474 z_shell_log_backend_disable(sh->log_backend);
1475 }
1476
1477 return 0;
1478 }
1479
shell_process(const struct shell * sh)1480 void shell_process(const struct shell *sh)
1481 {
1482 __ASSERT_NO_MSG(sh);
1483 __ASSERT_NO_MSG(sh->ctx);
1484
1485 /* atomically set the processing flag */
1486 z_flag_processing_set(sh, true);
1487
1488 switch (sh->ctx->state) {
1489 case SHELL_STATE_UNINITIALIZED:
1490 case SHELL_STATE_INITIALIZED:
1491 /* Console initialized but not started. */
1492 break;
1493
1494 case SHELL_STATE_ACTIVE:
1495 state_collect(sh);
1496 break;
1497 default:
1498 break;
1499 }
1500
1501 /* atomically clear the processing flag */
1502 z_flag_processing_set(sh, false);
1503 }
1504
shell_backend_get_by_name(const char * backend_name)1505 const struct shell *shell_backend_get_by_name(const char *backend_name)
1506 {
1507 STRUCT_SECTION_FOREACH(shell, backend) {
1508 if (strcmp(backend_name, backend->name) == 0) {
1509 return backend;
1510 }
1511 }
1512
1513 return NULL;
1514 }
1515
1516 /* This function mustn't be used from shell context to avoid deadlock.
1517 * However it can be used in shell command handlers.
1518 */
shell_vfprintf(const struct shell * sh,enum shell_vt100_color color,const char * fmt,va_list args)1519 void shell_vfprintf(const struct shell *sh, enum shell_vt100_color color,
1520 const char *fmt, va_list args)
1521 {
1522 __ASSERT_NO_MSG(sh);
1523 __ASSERT(!k_is_in_isr(), "Thread context required.");
1524 __ASSERT_NO_MSG(sh->ctx);
1525 __ASSERT_NO_MSG(z_flag_cmd_ctx_get(sh) ||
1526 (k_current_get() != sh->ctx->tid));
1527 __ASSERT_NO_MSG(sh->fprintf_ctx);
1528 __ASSERT_NO_MSG(fmt);
1529
1530 /* Sending a message to a non-active shell leads to a dead lock. */
1531 if (state_get(sh) != SHELL_STATE_ACTIVE) {
1532 z_flag_print_noinit_set(sh, true);
1533 return;
1534 }
1535
1536 k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER);
1537 if (!z_flag_cmd_ctx_get(sh) && !sh->ctx->bypass && z_flag_use_vt100_get(sh)) {
1538 z_shell_cmd_line_erase(sh);
1539 }
1540 z_shell_vfprintf(sh, color, fmt, args);
1541 if (!z_flag_cmd_ctx_get(sh) && !sh->ctx->bypass && z_flag_use_vt100_get(sh)) {
1542 z_shell_print_prompt_and_cmd(sh);
1543 }
1544 z_transport_buffer_flush(sh);
1545 k_mutex_unlock(&sh->ctx->wr_mtx);
1546 }
1547
1548 /* These functions mustn't be used from shell context to avoid deadlock:
1549 * - shell_fprintf_impl
1550 * - shell_info_impl
1551 * - shell_print_impl
1552 * - shell_warn_impl
1553 * - shell_error_impl
1554 * However, they can be used in shell command handlers.
1555 */
shell_fprintf_impl(const struct shell * sh,enum shell_vt100_color color,const char * fmt,...)1556 void shell_fprintf_impl(const struct shell *sh, enum shell_vt100_color color,
1557 const char *fmt, ...)
1558 {
1559 va_list args;
1560
1561 va_start(args, fmt);
1562 shell_vfprintf(sh, color, fmt, args);
1563 va_end(args);
1564 }
1565
shell_info_impl(const struct shell * sh,const char * fmt,...)1566 void shell_info_impl(const struct shell *sh, const char *fmt, ...)
1567 {
1568 va_list args;
1569
1570 va_start(args, fmt);
1571 shell_vfprintf(sh, SHELL_INFO, fmt, args);
1572 va_end(args);
1573 }
1574
shell_print_impl(const struct shell * sh,const char * fmt,...)1575 void shell_print_impl(const struct shell *sh, const char *fmt, ...)
1576 {
1577 va_list args;
1578
1579 va_start(args, fmt);
1580 shell_vfprintf(sh, SHELL_NORMAL, fmt, args);
1581 va_end(args);
1582 }
1583
shell_warn_impl(const struct shell * sh,const char * fmt,...)1584 void shell_warn_impl(const struct shell *sh, const char *fmt, ...)
1585 {
1586 va_list args;
1587
1588 va_start(args, fmt);
1589 shell_vfprintf(sh, SHELL_WARNING, fmt, args);
1590 va_end(args);
1591 }
1592
shell_error_impl(const struct shell * sh,const char * fmt,...)1593 void shell_error_impl(const struct shell *sh, const char *fmt, ...)
1594 {
1595 va_list args;
1596
1597 va_start(args, fmt);
1598 shell_vfprintf(sh, SHELL_ERROR, fmt, args);
1599 va_end(args);
1600 }
1601
shell_hexdump_line(const struct shell * sh,unsigned int offset,const uint8_t * data,size_t len)1602 void shell_hexdump_line(const struct shell *sh, unsigned int offset,
1603 const uint8_t *data, size_t len)
1604 {
1605 __ASSERT_NO_MSG(sh);
1606
1607 int i;
1608
1609 shell_print_impl(sh, "%08X: ", offset);
1610
1611 for (i = 0; i < SHELL_HEXDUMP_BYTES_IN_LINE; i++) {
1612 if (i > 0 && !(i % 8)) {
1613 shell_print_impl(sh, " ");
1614 }
1615
1616 if (i < len) {
1617 shell_print_impl(sh, "%02x ",
1618 data[i] & 0xFF);
1619 } else {
1620 shell_print_impl(sh, " ");
1621 }
1622 }
1623
1624 shell_print_impl(sh, "|");
1625
1626 for (i = 0; i < SHELL_HEXDUMP_BYTES_IN_LINE; i++) {
1627 if (i > 0 && !(i % 8)) {
1628 shell_print_impl(sh, " ");
1629 }
1630
1631 if (i < len) {
1632 char c = data[i];
1633
1634 shell_print_impl(sh, "%c",
1635 isprint((int)c) != 0 ? c : '.');
1636 } else {
1637 shell_print_impl(sh, " ");
1638 }
1639 }
1640
1641 shell_print(sh, "|");
1642 }
1643
shell_hexdump(const struct shell * sh,const uint8_t * data,size_t len)1644 void shell_hexdump(const struct shell *sh, const uint8_t *data, size_t len)
1645 {
1646 __ASSERT_NO_MSG(sh);
1647
1648 const uint8_t *p = data;
1649 size_t line_len;
1650
1651 while (len) {
1652 line_len = MIN(len, SHELL_HEXDUMP_BYTES_IN_LINE);
1653
1654 shell_hexdump_line(sh, p - data, p, line_len);
1655
1656 len -= line_len;
1657 p += line_len;
1658 }
1659 }
1660
shell_prompt_change(const struct shell * sh,const char * prompt)1661 int shell_prompt_change(const struct shell *sh, const char *prompt)
1662 {
1663 #if defined(CONFIG_SHELL_PROMPT_CHANGE) && CONFIG_SHELL_PROMPT_CHANGE
1664 __ASSERT_NO_MSG(sh);
1665
1666 if (prompt == NULL) {
1667 return -EINVAL;
1668 }
1669
1670 static const size_t mtx_timeout_ms = 20;
1671 size_t prompt_length = z_shell_strlen(prompt);
1672
1673 if (k_mutex_lock(&sh->ctx->wr_mtx, K_MSEC(mtx_timeout_ms))) {
1674 return -EBUSY;
1675 }
1676
1677 if ((prompt_length + 1 > CONFIG_SHELL_PROMPT_BUFF_SIZE) || (prompt_length == 0)) {
1678 k_mutex_unlock(&sh->ctx->wr_mtx);
1679 return -EINVAL;
1680 }
1681
1682 strcpy(sh->ctx->prompt, prompt);
1683
1684 sh->ctx->vt100_ctx.cons.name_len = prompt_length;
1685
1686 k_mutex_unlock(&sh->ctx->wr_mtx);
1687
1688 return 0;
1689 #else
1690 return -EPERM;
1691 #endif
1692 }
1693
shell_help(const struct shell * sh)1694 void shell_help(const struct shell *sh)
1695 {
1696 k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER);
1697 shell_internal_help_print(sh);
1698 k_mutex_unlock(&sh->ctx->wr_mtx);
1699 }
1700
shell_execute_cmd(const struct shell * sh,const char * cmd)1701 int shell_execute_cmd(const struct shell *sh, const char *cmd)
1702 {
1703 uint16_t cmd_len = z_shell_strlen(cmd);
1704 int ret_val;
1705
1706 if (cmd == NULL) {
1707 return -ENOEXEC;
1708 }
1709
1710 if (cmd_len > (CONFIG_SHELL_CMD_BUFF_SIZE - 1)) {
1711 return -ENOMEM;
1712 }
1713
1714 if (sh == NULL) {
1715 #if defined(CONFIG_SHELL_BACKEND_DUMMY)
1716 sh = shell_backend_dummy_get_ptr();
1717 #else
1718 return -EINVAL;
1719 #endif
1720 }
1721
1722 __ASSERT(!z_flag_cmd_ctx_get(sh), "Function cannot be called"
1723 " from command context");
1724
1725 strcpy(sh->ctx->cmd_buff, cmd);
1726 sh->ctx->cmd_buff_len = cmd_len;
1727 sh->ctx->cmd_buff_pos = cmd_len;
1728
1729 k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER);
1730 ret_val = execute(sh);
1731 k_mutex_unlock(&sh->ctx->wr_mtx);
1732
1733 cmd_buffer_clear(sh);
1734
1735 return ret_val;
1736 }
1737
shell_insert_mode_set(const struct shell * sh,bool val)1738 int shell_insert_mode_set(const struct shell *sh, bool val)
1739 {
1740 if (sh == NULL) {
1741 return -EINVAL;
1742 }
1743
1744 return (int)z_flag_insert_mode_set(sh, val);
1745 }
1746
shell_use_colors_set(const struct shell * sh,bool val)1747 int shell_use_colors_set(const struct shell *sh, bool val)
1748 {
1749 if (sh == NULL) {
1750 return -EINVAL;
1751 }
1752
1753 return (int)z_flag_use_colors_set(sh, val);
1754 }
1755
shell_use_vt100_set(const struct shell * sh,bool val)1756 int shell_use_vt100_set(const struct shell *sh, bool val)
1757 {
1758 if (sh == NULL) {
1759 return -EINVAL;
1760 }
1761
1762 return (int)z_flag_use_vt100_set(sh, val);
1763 }
1764
shell_get_return_value(const struct shell * sh)1765 int shell_get_return_value(const struct shell *sh)
1766 {
1767 if (sh == NULL) {
1768 return -EINVAL;
1769 }
1770
1771 return z_shell_get_return_value(sh);
1772 }
1773
shell_echo_set(const struct shell * sh,bool val)1774 int shell_echo_set(const struct shell *sh, bool val)
1775 {
1776 if (sh == NULL) {
1777 return -EINVAL;
1778 }
1779
1780 return (int)z_flag_echo_set(sh, val);
1781 }
1782
shell_obscure_set(const struct shell * sh,bool val)1783 int shell_obscure_set(const struct shell *sh, bool val)
1784 {
1785 if (sh == NULL) {
1786 return -EINVAL;
1787 }
1788
1789 return (int)z_flag_obscure_set(sh, val);
1790 }
1791
shell_mode_delete_set(const struct shell * sh,bool val)1792 int shell_mode_delete_set(const struct shell *sh, bool val)
1793 {
1794 if (sh == NULL) {
1795 return -EINVAL;
1796 }
1797
1798 return (int)z_flag_mode_delete_set(sh, val);
1799 }
1800
shell_set_bypass(const struct shell * sh,shell_bypass_cb_t bypass)1801 void shell_set_bypass(const struct shell *sh, shell_bypass_cb_t bypass)
1802 {
1803 __ASSERT_NO_MSG(sh);
1804
1805 sh->ctx->bypass = bypass;
1806
1807 if (bypass == NULL) {
1808 cmd_buffer_clear(sh);
1809 }
1810 }
1811
shell_ready(const struct shell * sh)1812 bool shell_ready(const struct shell *sh)
1813 {
1814 __ASSERT_NO_MSG(sh);
1815
1816 return state_get(sh) == SHELL_STATE_ACTIVE;
1817 }
1818
cmd_help(const struct shell * sh,size_t argc,char ** argv)1819 static int cmd_help(const struct shell *sh, size_t argc, char **argv)
1820 {
1821 ARG_UNUSED(argc);
1822 ARG_UNUSED(argv);
1823
1824 #if defined(CONFIG_SHELL_TAB)
1825 shell_print(sh, "Please press the <Tab> button to see all available "
1826 "commands.");
1827 #endif
1828
1829 #if defined(CONFIG_SHELL_TAB_AUTOCOMPLETION)
1830 shell_print(sh,
1831 "You can also use the <Tab> button to prompt or auto-complete"
1832 " all commands or its subcommands.");
1833 #endif
1834
1835 #if defined(CONFIG_SHELL_HELP)
1836 shell_print(sh,
1837 "You can try to call commands with <-h> or <--help> parameter"
1838 " for more information.");
1839 #endif
1840
1841 #if defined(CONFIG_SHELL_METAKEYS)
1842 shell_print(sh,
1843 "\nShell supports following meta-keys:\n"
1844 " Ctrl + (a key from: abcdefklnpuw)\n"
1845 " Alt + (a key from: bf)\n"
1846 "Please refer to shell documentation for more details.");
1847 #endif
1848
1849 if (IS_ENABLED(CONFIG_SHELL_HELP)) {
1850 /* For NULL argument function will print all root commands */
1851 z_shell_help_subcmd_print(sh, NULL,
1852 "\nAvailable commands:\n");
1853 } else {
1854 const struct shell_static_entry *entry;
1855 size_t idx = 0;
1856
1857 shell_print(sh, "\nAvailable commands:");
1858 while ((entry = z_shell_cmd_get(NULL, idx++, NULL)) != NULL) {
1859 shell_print(sh, " %s", entry->syntax);
1860 }
1861 }
1862
1863 return 0;
1864 }
1865
1866 SHELL_CMD_ARG_REGISTER(help, NULL, "Prints the help message.", cmd_help, 1, 0);
1867