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