cli: modern_hush: Add upstream commits up to 2nd October 2023.
[pandora-u-boot.git] / common / cli_hush_modern.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * This file defines the compilation unit for the new hush shell version.  The
4  * actual implementation from upstream BusyBox can be found in
5  * `cli_hush_upstream.c` which is included at the end of this file.
6  *
7  * This "wrapper" technique is used to keep the changes to the upstream version
8  * as minmal as possible.  Instead, all defines and redefines necessary are done
9  * here, outside the upstream sources.  This will hopefully make upgrades to
10  * newer revisions much easier.
11  *
12  * Copyright (c) 2021, Harald Seiler, DENX Software Engineering, hws@denx.de
13  */
14
15 #include <common.h>         /* readline */
16 #include <env.h>
17 #include <malloc.h>         /* malloc, free, realloc*/
18 #include <linux/ctype.h>    /* isalpha, isdigit */
19 #include <console.h>
20 #include <bootretry.h>
21 #include <cli.h>
22 #include <cli_hush.h>
23 #include <command.h>        /* find_cmd */
24 #include <asm/global_data.h>
25
26 /*
27  * BusyBox Version: UPDATE THIS WHEN PULLING NEW UPSTREAM REVISION!
28  */
29 #define BB_VER                  "1.35.0.git7d1c7d833785"
30
31 /*
32  * Define hush features by the names used upstream.
33  */
34 #define ENABLE_HUSH_INTERACTIVE 1
35 #define ENABLE_FEATURE_EDITING  1
36 #define ENABLE_HUSH_IF          1
37 #define ENABLE_HUSH_LOOPS       1
38 /* No MMU in U-Boot */
39 #define BB_MMU                  0
40 #define USE_FOR_NOMMU(...)      __VA_ARGS__
41 #define USE_FOR_MMU(...)
42
43 /*
44  * Size-saving "small" ints (arch-dependent)
45  */
46 #if CONFIG_IS_ENABLED(X86) || CONFIG_IS_ENABLED(X86_64) || CONFIG_IS_ENABLED(MIPS)
47 /* add other arches which benefit from this... */
48 typedef signed char smallint;
49 typedef unsigned char smalluint;
50 #else
51 /* for arches where byte accesses generate larger code: */
52 typedef int smallint;
53 typedef unsigned smalluint;
54 #endif
55
56 /*
57  * Alignment defines used by BusyBox.
58  */
59 #define ALIGN1                  __attribute__((aligned(1)))
60 #define ALIGN2                  __attribute__((aligned(2)))
61 #define ALIGN4                  __attribute__((aligned(4)))
62 #define ALIGN8                  __attribute__((aligned(8)))
63 #define ALIGN_PTR               __attribute__((aligned(sizeof(void*))))
64
65 /*
66  * Miscellaneous compiler/platform defines.
67  */
68 #define FAST_FUNC /* not used in U-Boot */
69 #define UNUSED_PARAM            __always_unused
70 #define ALWAYS_INLINE           __always_inline
71 #define NOINLINE                noinline
72
73 /*
74  * Defines to provide equivalents to what libc/BusyBox defines.
75  */
76 #define EOF                     (-1)
77 #define EXIT_SUCCESS            0
78 #define EXIT_FAILURE            1
79
80 /*
81  * Stubs to provide libc/BusyBox functions based on U-Boot equivalents where it
82  * makes sense.
83  */
84 #define utoa                    simple_itoa
85
86 static void __noreturn xfunc_die(void)
87 {
88         panic("HUSH died!");
89 }
90
91 #define bb_error_msg_and_die(format, ...) do { \
92 panic("HUSH: " format, __VA_ARGS__); \
93 } while (0);
94
95 #define bb_simple_error_msg_and_die(msg) do { \
96 panic_str("HUSH: " msg); \
97 } while (0);
98
99 /* fdprintf() is used for debug output. */
100 static int __maybe_unused fdprintf(int fd, const char *format, ...)
101 {
102         va_list args;
103         uint i;
104
105         assert(fd == 2);
106
107         va_start(args, format);
108         i = vprintf(format, args);
109         va_end(args);
110
111         return i;
112 }
113
114 static void bb_verror_msg(const char *s, va_list p, const char* strerr)
115 {
116         /* TODO: what to do with strerr arg? */
117         vprintf(s, p);
118 }
119
120 static void bb_error_msg(const char *s, ...)
121 {
122         va_list p;
123
124         va_start(p, s);
125         bb_verror_msg(s, p, NULL);
126         va_end(p);
127 }
128
129 static void bb_simple_error_msg(const char *s)
130 {
131         bb_error_msg("%s", s);
132 }
133
134 static void *xmalloc(size_t size)
135 {
136         void *p = NULL;
137         if (!(p = malloc(size)))
138                 panic("out of memory");
139         return p;
140 }
141
142 static void *xzalloc(size_t size)
143 {
144         void *p = xmalloc(size);
145         memset(p, 0, size);
146         return p;
147 }
148
149 static void *xrealloc(void *ptr, size_t size)
150 {
151         void *p = NULL;
152         if (!(p = realloc(ptr, size)))
153                 panic("out of memory");
154         return p;
155 }
156
157 static void *xmemdup(const void *s, int n)
158 {
159         return memcpy(xmalloc(n), s, n);
160 }
161
162 #define xstrdup         strdup
163 #define xstrndup        strndup
164
165 static void *mempcpy(void *dest, const void *src, size_t len)
166 {
167         return memcpy(dest, src, len) + len;
168 }
169
170 /* Like strcpy but can copy overlapping strings. */
171 static void overlapping_strcpy(char *dst, const char *src)
172 {
173         /*
174          * Cheap optimization for dst == src case -
175          * better to have it here than in many callers.
176          */
177         if (dst != src) {
178                 while ((*dst = *src) != '\0') {
179                         dst++;
180                         src++;
181                 }
182         }
183 }
184
185 static char* skip_whitespace(const char *s)
186 {
187         /*
188          * In POSIX/C locale (the only locale we care about: do we REALLY want
189          * to allow Unicode whitespace in, say, .conf files? nuts!)
190          * isspace is only these chars: "\t\n\v\f\r" and space.
191          * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13.
192          * Use that.
193          */
194         while (*s == ' ' || (unsigned char)(*s - 9) <= (13 - 9))
195                 s++;
196
197         return (char *) s;
198 }
199
200 static char* skip_non_whitespace(const char *s)
201 {
202         while (*s != '\0' && *s != ' ' && (unsigned char)(*s - 9) > (13 - 9))
203                 s++;
204
205         return (char *) s;
206 }
207
208 #define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
209 #define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
210
211 static const char* endofname(const char *name)
212 {
213         if (!is_name(*name))
214                 return name;
215         while (*++name) {
216                 if (!is_in_name(*name))
217                         break;
218         }
219         return name;
220 }
221
222 /**
223  * list_size() - returns the number of elements in char ** before NULL.
224  *
225  * Argument must contain NULL to signalize its end.
226  *
227  * @list The list to count the number of element.
228  * @return The number of element in list.
229  */
230 static size_t list_size(char **list)
231 {
232         size_t size;
233
234         for (size = 0; list[size] != NULL; size++);
235
236         return size;
237 }
238
239 static int varcmp(const char *p, const char *q)
240 {
241         int c, d;
242
243         while ((c = *p) == (d = *q)) {
244                 if (c == '\0' || c == '=')
245                         goto out;
246                 p++;
247                 q++;
248         }
249         if (c == '=')
250                 c = '\0';
251         if (d == '=')
252                 d = '\0';
253 out:
254         return c - d;
255 }
256
257 struct in_str;
258 static int u_boot_cli_readline(struct in_str *i);
259
260 struct in_str;
261 static int u_boot_cli_readline(struct in_str *i);
262
263 /*
264  * BusyBox globals which are needed for hush.
265  */
266 static uint8_t xfunc_error_retval;
267
268 static const char defifsvar[] __aligned(1) = "IFS= \t\n";
269 #define defifs (defifsvar + 4)
270
271 /* This define is used to check if exit command was called. */
272 #define EXIT_RET_CODE -2
273
274 /*
275  * This define is used for changes that need be done directly in the upstream
276  * sources still. Ideally, its use should be minimized as much as possible.
277  */
278 #define __U_BOOT__
279
280 /*
281  *
282  * +-- Include of the upstream sources --+ *
283  * V                                     V
284  */
285 #include "cli_hush_upstream.c"
286 /*
287  * A                                     A
288  * +-- Include of the upstream sources --+ *
289  *
290  */
291
292 int u_boot_hush_start_modern(void)
293 {
294         INIT_G();
295         return 0;
296 }
297
298 static int u_boot_cli_readline(struct in_str *i)
299 {
300         char *prompt;
301         char __maybe_unused *ps_prompt = NULL;
302
303         if (!G.promptmode)
304                 prompt = CONFIG_SYS_PROMPT;
305 #ifdef CONFIG_SYS_PROMPT_HUSH_PS2
306         else
307                 prompt = CONFIG_SYS_PROMPT_HUSH_PS2;
308 #else
309         /* TODO: default value? */
310         #error "SYS_PROMPT_HUSH_PS2 is not defined!"
311 #endif
312
313         if (CONFIG_IS_ENABLED(CMDLINE_PS_SUPPORT)) {
314                 if (!G.promptmode)
315                         ps_prompt = env_get("PS1");
316                 else
317                         ps_prompt = env_get("PS2");
318
319                 if (ps_prompt)
320                         prompt = ps_prompt;
321         }
322
323         return cli_readline(prompt);
324 }