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