xref: /openbmc/u-boot/common/cli.c (revision 14453fbfadc2f98ca35d6033140466c7a4b4947a)
1  // SPDX-License-Identifier: GPL-2.0+
2  /*
3   * (C) Copyright 2000
4   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5   *
6   * Add to readline cmdline-editing by
7   * (C) Copyright 2005
8   * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
9   */
10  
11  #include <common.h>
12  #include <cli.h>
13  #include <cli_hush.h>
14  #include <console.h>
15  #include <fdtdec.h>
16  #include <malloc.h>
17  
18  DECLARE_GLOBAL_DATA_PTR;
19  
20  #ifdef CONFIG_CMDLINE
21  /*
22   * Run a command using the selected parser.
23   *
24   * @param cmd	Command to run
25   * @param flag	Execution flags (CMD_FLAG_...)
26   * @return 0 on success, or != 0 on error.
27   */
28  int run_command(const char *cmd, int flag)
29  {
30  #if !CONFIG_IS_ENABLED(HUSH_PARSER)
31  	/*
32  	 * cli_run_command can return 0 or 1 for success, so clean up
33  	 * its result.
34  	 */
35  	if (cli_simple_run_command(cmd, flag) == -1)
36  		return 1;
37  
38  	return 0;
39  #else
40  	int hush_flags = FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP;
41  
42  	if (flag & CMD_FLAG_ENV)
43  		hush_flags |= FLAG_CONT_ON_NEWLINE;
44  	return parse_string_outer(cmd, hush_flags);
45  #endif
46  }
47  
48  /*
49   * Run a command using the selected parser, and check if it is repeatable.
50   *
51   * @param cmd	Command to run
52   * @param flag	Execution flags (CMD_FLAG_...)
53   * @return 0 (not repeatable) or 1 (repeatable) on success, -1 on error.
54   */
55  int run_command_repeatable(const char *cmd, int flag)
56  {
57  #ifndef CONFIG_HUSH_PARSER
58  	return cli_simple_run_command(cmd, flag);
59  #else
60  	/*
61  	 * parse_string_outer() returns 1 for failure, so clean up
62  	 * its result.
63  	 */
64  	if (parse_string_outer(cmd,
65  			       FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP))
66  		return -1;
67  
68  	return 0;
69  #endif
70  }
71  #endif /* CONFIG_CMDLINE */
72  
73  int run_command_list(const char *cmd, int len, int flag)
74  {
75  	int need_buff = 1;
76  	char *buff = (char *)cmd;	/* cast away const */
77  	int rcode = 0;
78  
79  	if (len == -1) {
80  		len = strlen(cmd);
81  #ifdef CONFIG_HUSH_PARSER
82  		/* hush will never change our string */
83  		need_buff = 0;
84  #else
85  		/* the built-in parser will change our string if it sees \n */
86  		need_buff = strchr(cmd, '\n') != NULL;
87  #endif
88  	}
89  	if (need_buff) {
90  		buff = malloc(len + 1);
91  		if (!buff)
92  			return 1;
93  		memcpy(buff, cmd, len);
94  		buff[len] = '\0';
95  	}
96  #ifdef CONFIG_HUSH_PARSER
97  	rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON);
98  #else
99  	/*
100  	 * This function will overwrite any \n it sees with a \0, which
101  	 * is why it can't work with a const char *. Here we are making
102  	 * using of internal knowledge of this function, to avoid always
103  	 * doing a malloc() which is actually required only in a case that
104  	 * is pretty rare.
105  	 */
106  #ifdef CONFIG_CMDLINE
107  	rcode = cli_simple_run_command_list(buff, flag);
108  #else
109  	rcode = board_run_command(buff);
110  #endif
111  #endif
112  	if (need_buff)
113  		free(buff);
114  
115  	return rcode;
116  }
117  
118  /****************************************************************************/
119  
120  #if defined(CONFIG_CMD_RUN)
121  int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
122  {
123  	int i;
124  
125  	if (argc < 2)
126  		return CMD_RET_USAGE;
127  
128  	for (i = 1; i < argc; ++i) {
129  		char *arg;
130  
131  		arg = env_get(argv[i]);
132  		if (arg == NULL) {
133  			printf("## Error: \"%s\" not defined\n", argv[i]);
134  			return 1;
135  		}
136  
137  		if (run_command(arg, flag | CMD_FLAG_ENV) != 0)
138  			return 1;
139  	}
140  	return 0;
141  }
142  #endif
143  
144  #if CONFIG_IS_ENABLED(OF_CONTROL)
145  bool cli_process_fdt(const char **cmdp)
146  {
147  	/* Allow the fdt to override the boot command */
148  	char *env = fdtdec_get_config_string(gd->fdt_blob, "bootcmd");
149  	if (env)
150  		*cmdp = env;
151  	/*
152  	 * If the bootsecure option was chosen, use secure_boot_cmd().
153  	 * Always use 'env' in this case, since bootsecure requres that the
154  	 * bootcmd was specified in the FDT too.
155  	 */
156  	return fdtdec_get_config_int(gd->fdt_blob, "bootsecure", 0) != 0;
157  }
158  
159  /*
160   * Runs the given boot command securely.  Specifically:
161   * - Doesn't run the command with the shell (run_command or parse_string_outer),
162   *   since that's a lot of code surface that an attacker might exploit.
163   *   Because of this, we don't do any argument parsing--the secure boot command
164   *   has to be a full-fledged u-boot command.
165   * - Doesn't check for keypresses before booting, since that could be a
166   *   security hole; also disables Ctrl-C.
167   * - Doesn't allow the command to return.
168   *
169   * Upon any failures, this function will drop into an infinite loop after
170   * printing the error message to console.
171   */
172  void cli_secure_boot_cmd(const char *cmd)
173  {
174  #ifdef CONFIG_CMDLINE
175  	cmd_tbl_t *cmdtp;
176  #endif
177  	int rc;
178  
179  	if (!cmd) {
180  		printf("## Error: Secure boot command not specified\n");
181  		goto err;
182  	}
183  
184  	/* Disable Ctrl-C just in case some command is used that checks it. */
185  	disable_ctrlc(1);
186  
187  	/* Find the command directly. */
188  #ifdef CONFIG_CMDLINE
189  	cmdtp = find_cmd(cmd);
190  	if (!cmdtp) {
191  		printf("## Error: \"%s\" not defined\n", cmd);
192  		goto err;
193  	}
194  
195  	/* Run the command, forcing no flags and faking argc and argv. */
196  	rc = (cmdtp->cmd)(cmdtp, 0, 1, (char **)&cmd);
197  
198  #else
199  	rc = board_run_command(cmd);
200  #endif
201  
202  	/* Shouldn't ever return from boot command. */
203  	printf("## Error: \"%s\" returned (code %d)\n", cmd, rc);
204  
205  err:
206  	/*
207  	 * Not a whole lot to do here.  Rebooting won't help much, since we'll
208  	 * just end up right back here.  Just loop.
209  	 */
210  	hang();
211  }
212  #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
213  
214  void cli_loop(void)
215  {
216  #ifdef CONFIG_HUSH_PARSER
217  	parse_file_outer();
218  	/* This point is never reached */
219  	for (;;);
220  #elif defined(CONFIG_CMDLINE)
221  	cli_simple_loop();
222  #else
223  	printf("## U-Boot command line is disabled. Please enable CONFIG_CMDLINE\n");
224  #endif /*CONFIG_HUSH_PARSER*/
225  }
226  
227  void cli_init(void)
228  {
229  #ifdef CONFIG_HUSH_PARSER
230  	u_boot_hush_start();
231  #endif
232  
233  #if defined(CONFIG_HUSH_INIT_VAR)
234  	hush_init_var();
235  #endif
236  }
237