ARM: renesas: Drop unused mmc.h
[pandora-u-boot.git] / common / cli.c
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 #define pr_fmt(fmt) "cli: %s: " fmt, __func__
12
13 #include <common.h>
14 #include <bootstage.h>
15 #include <cli.h>
16 #include <cli_hush.h>
17 #include <command.h>
18 #include <console.h>
19 #include <env.h>
20 #include <fdtdec.h>
21 #include <hang.h>
22 #include <malloc.h>
23 #include <asm/global_data.h>
24 #include <dm/ofnode.h>
25 #include <linux/errno.h>
26
27 #ifdef CONFIG_CMDLINE
28
29 static inline bool use_hush_old(void)
30 {
31         return IS_ENABLED(CONFIG_HUSH_SELECTABLE) ?
32         gd->flags & GD_FLG_HUSH_OLD_PARSER :
33         IS_ENABLED(CONFIG_HUSH_OLD_PARSER);
34 }
35
36 /*
37  * Run a command using the selected parser.
38  *
39  * @param cmd   Command to run
40  * @param flag  Execution flags (CMD_FLAG_...)
41  * Return: 0 on success, or != 0 on error.
42  */
43 int run_command(const char *cmd, int flag)
44 {
45 #if !IS_ENABLED(CONFIG_HUSH_PARSER)
46         /*
47          * cli_run_command can return 0 or 1 for success, so clean up
48          * its result.
49          */
50         if (cli_simple_run_command(cmd, flag) == -1)
51                 return 1;
52
53         return 0;
54 #else
55         if (use_hush_old()) {
56                 int hush_flags = FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP;
57
58                 if (flag & CMD_FLAG_ENV)
59                         hush_flags |= FLAG_CONT_ON_NEWLINE;
60                 return parse_string_outer(cmd, hush_flags);
61         }
62         /*
63          * Possible values for flags are the following:
64          * FLAG_EXIT_FROM_LOOP: This flags ensures we exit from loop in
65          * parse_and_run_stream() after first iteration while normal
66          * behavior, * i.e. when called from cli_loop(), is to loop
67          * infinitely.
68          * FLAG_PARSE_SEMICOLON: modern Hush parses ';' and does not stop
69          * first time it sees one. So, I think we do not need this flag.
70          * FLAG_REPARSING: For the moment, I do not understand the goal
71          * of this flag.
72          * FLAG_CONT_ON_NEWLINE: This flag seems to be used to continue
73          * parsing even when reading '\n' when coming from
74          * run_command(). In this case, modern Hush reads until it finds
75          * '\0'. So, I think we do not need this flag.
76          */
77         return parse_string_outer_modern(cmd, FLAG_EXIT_FROM_LOOP);
78 #endif
79 }
80
81 /*
82  * Run a command using the selected parser, and check if it is repeatable.
83  *
84  * @param cmd   Command to run
85  * @param flag  Execution flags (CMD_FLAG_...)
86  * Return: 0 (not repeatable) or 1 (repeatable) on success, -1 on error.
87  */
88 int run_command_repeatable(const char *cmd, int flag)
89 {
90 #ifndef CONFIG_HUSH_PARSER
91         return cli_simple_run_command(cmd, flag);
92 #else
93         int ret;
94
95         if (use_hush_old()) {
96                 ret = parse_string_outer(cmd,
97                                          FLAG_PARSE_SEMICOLON
98                                          | FLAG_EXIT_FROM_LOOP);
99         } else {
100                 ret = parse_string_outer_modern(cmd,
101                                               FLAG_PARSE_SEMICOLON
102                                               | FLAG_EXIT_FROM_LOOP);
103         }
104
105         /*
106          * parse_string_outer() returns 1 for failure, so clean up
107          * its result.
108          */
109         if (ret)
110                 return -1;
111
112         return 0;
113 #endif
114 }
115 #else
116 __weak int board_run_command(const char *cmdline)
117 {
118         printf("## Commands are disabled. Please enable CONFIG_CMDLINE.\n");
119
120         return 1;
121 }
122 #endif /* CONFIG_CMDLINE */
123
124 int run_command_list(const char *cmd, int len, int flag)
125 {
126         int need_buff = 1;
127         char *buff = (char *)cmd;       /* cast away const */
128         int rcode = 0;
129
130         if (len == -1) {
131                 len = strlen(cmd);
132 #ifdef CONFIG_HUSH_PARSER
133                 /* hush will never change our string */
134                 need_buff = 0;
135 #else
136                 /* the built-in parser will change our string if it sees \n */
137                 need_buff = strchr(cmd, '\n') != NULL;
138 #endif
139         }
140         if (need_buff) {
141                 buff = malloc(len + 1);
142                 if (!buff)
143                         return 1;
144                 memcpy(buff, cmd, len);
145                 buff[len] = '\0';
146         }
147 #ifdef CONFIG_HUSH_PARSER
148         if (use_hush_old()) {
149                 rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON);
150         } else {
151                 rcode = parse_string_outer_modern(buff, FLAG_PARSE_SEMICOLON);
152         }
153 #else
154         /*
155          * This function will overwrite any \n it sees with a \0, which
156          * is why it can't work with a const char *. Here we are making
157          * using of internal knowledge of this function, to avoid always
158          * doing a malloc() which is actually required only in a case that
159          * is pretty rare.
160          */
161 #ifdef CONFIG_CMDLINE
162         rcode = cli_simple_run_command_list(buff, flag);
163 #else
164         rcode = board_run_command(buff);
165 #endif
166 #endif
167         if (need_buff)
168                 free(buff);
169
170         return rcode;
171 }
172
173 int run_commandf(const char *fmt, ...)
174 {
175         va_list args;
176         int nbytes;
177
178         va_start(args, fmt);
179         /*
180          * Limit the console_buffer space being used to CONFIG_SYS_CBSIZE,
181          * because its last byte is used to fit the replacement of \0 by \n\0
182          * in underlying hush parser
183          */
184         nbytes = vsnprintf(console_buffer, CONFIG_SYS_CBSIZE, fmt, args);
185         va_end(args);
186
187         if (nbytes < 0) {
188                 pr_debug("I/O internal error occurred.\n");
189                 return -EIO;
190         } else if (nbytes >= CONFIG_SYS_CBSIZE) {
191                 pr_debug("'fmt' size:%d exceeds the limit(%d)\n",
192                          nbytes, CONFIG_SYS_CBSIZE);
193                 return -ENOSPC;
194         }
195         return run_command(console_buffer, 0);
196 }
197
198 /****************************************************************************/
199
200 #if defined(CONFIG_CMD_RUN)
201 int do_run(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
202 {
203         int i, ret;
204
205         if (argc < 2)
206                 return CMD_RET_USAGE;
207
208         for (i = 1; i < argc; ++i) {
209                 char *arg;
210
211                 arg = env_get(argv[i]);
212                 if (arg == NULL) {
213                         printf("## Error: \"%s\" not defined\n", argv[i]);
214                         return 1;
215                 }
216
217                 ret = run_command(arg, flag | CMD_FLAG_ENV);
218                 if (ret)
219                         return ret;
220         }
221         return 0;
222 }
223 #endif
224
225 #if CONFIG_IS_ENABLED(OF_CONTROL)
226 bool cli_process_fdt(const char **cmdp)
227 {
228         /* Allow the fdt to override the boot command */
229         const char *env = ofnode_conf_read_str("bootcmd");
230         if (env)
231                 *cmdp = env;
232         /*
233          * If the bootsecure option was chosen, use secure_boot_cmd().
234          * Always use 'env' in this case, since bootsecure requres that the
235          * bootcmd was specified in the FDT too.
236          */
237         return ofnode_conf_read_int("bootsecure", 0);
238 }
239
240 /*
241  * Runs the given boot command securely.  Specifically:
242  * - Doesn't run the command with the shell (run_command or parse_string_outer),
243  *   since that's a lot of code surface that an attacker might exploit.
244  *   Because of this, we don't do any argument parsing--the secure boot command
245  *   has to be a full-fledged u-boot command.
246  * - Doesn't check for keypresses before booting, since that could be a
247  *   security hole; also disables Ctrl-C.
248  * - Doesn't allow the command to return.
249  *
250  * Upon any failures, this function will drop into an infinite loop after
251  * printing the error message to console.
252  */
253 void cli_secure_boot_cmd(const char *cmd)
254 {
255 #ifdef CONFIG_CMDLINE
256         struct cmd_tbl *cmdtp;
257 #endif
258         int rc;
259
260         if (!cmd) {
261                 printf("## Error: Secure boot command not specified\n");
262                 goto err;
263         }
264
265         /* Disable Ctrl-C just in case some command is used that checks it. */
266         disable_ctrlc(1);
267
268         /* Find the command directly. */
269 #ifdef CONFIG_CMDLINE
270         cmdtp = find_cmd(cmd);
271         if (!cmdtp) {
272                 printf("## Error: \"%s\" not defined\n", cmd);
273                 goto err;
274         }
275
276         /* Run the command, forcing no flags and faking argc and argv. */
277         rc = (cmdtp->cmd)(cmdtp, 0, 1, (char **)&cmd);
278
279 #else
280         rc = board_run_command(cmd);
281 #endif
282
283         /* Shouldn't ever return from boot command. */
284         printf("## Error: \"%s\" returned (code %d)\n", cmd, rc);
285
286 err:
287         /*
288          * Not a whole lot to do here.  Rebooting won't help much, since we'll
289          * just end up right back here.  Just loop.
290          */
291         hang();
292 }
293 #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
294
295 void cli_loop(void)
296 {
297         bootstage_mark(BOOTSTAGE_ID_ENTER_CLI_LOOP);
298 #if CONFIG_IS_ENABLED(HUSH_PARSER)
299         if (gd->flags & GD_FLG_HUSH_MODERN_PARSER)
300                 parse_and_run_file();
301         else if (gd->flags & GD_FLG_HUSH_OLD_PARSER)
302                 parse_file_outer();
303
304         printf("Problem\n");
305         /* This point is never reached */
306         for (;;);
307 #elif defined(CONFIG_CMDLINE)
308         cli_simple_loop();
309 #else
310         printf("## U-Boot command line is disabled. Please enable CONFIG_CMDLINE\n");
311 #endif /*CONFIG_HUSH_PARSER*/
312 }
313
314 void cli_init(void)
315 {
316 #ifdef CONFIG_HUSH_PARSER
317         /* This if block is used to initialize hush parser gd flag. */
318         if (!(gd->flags & GD_FLG_HUSH_OLD_PARSER)
319                 && !(gd->flags & GD_FLG_HUSH_MODERN_PARSER)) {
320                 if (CONFIG_IS_ENABLED(HUSH_OLD_PARSER))
321                         gd->flags |= GD_FLG_HUSH_OLD_PARSER;
322                 else if (CONFIG_IS_ENABLED(HUSH_MODERN_PARSER))
323                         gd->flags |= GD_FLG_HUSH_MODERN_PARSER;
324         }
325
326         if (gd->flags & GD_FLG_HUSH_OLD_PARSER) {
327                 u_boot_hush_start();
328         } else if (gd->flags & GD_FLG_HUSH_MODERN_PARSER) {
329                 u_boot_hush_start_modern();
330         } else {
331                 printf("No valid hush parser to use, cli will not initialized!\n");
332                 return;
333         }
334 #endif
335
336 #if defined(CONFIG_HUSH_INIT_VAR)
337         hush_init_var();
338 #endif
339 }