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