blob: fb578c38535926659e75b55aad629353eedec502 [file] [log] [blame]
Francis Laniel8197f012023-12-22 22:02:28 +01001// 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.34.0.git37460f5daff9"
30
31/*
32 * Define hush features by the names used upstream.
33 */
34#define ENABLE_HUSH_INTERACTIVE 1
35#define ENABLE_FEATURE_EDITING 1
Francis Laniel374b77e2023-12-22 22:02:39 +010036#define ENABLE_HUSH_IF 1
Francis Laniele252f502023-12-22 22:02:40 +010037#define ENABLE_HUSH_LOOPS 1
Francis Laniel8197f012023-12-22 22:02:28 +010038/* 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... */
48typedef signed char smallint;
49typedef unsigned char smalluint;
50#else
51/* for arches where byte accesses generate larger code: */
52typedef int smallint;
53typedef 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
86static void __noreturn xfunc_die(void)
87{
88 panic("HUSH died!");
89}
90
91#define bb_error_msg_and_die(format, ...) do { \
92panic("HUSH: " format, __VA_ARGS__); \
93} while (0);
94
95#define bb_simple_error_msg_and_die(msg) do { \
96panic_str("HUSH: " msg); \
97} while (0);
98
99/* fdprintf() is used for debug output. */
100static 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
114static 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
120static 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
Francis Laniel374b77e2023-12-22 22:02:39 +0100129static void bb_simple_error_msg(const char *s)
130{
131 bb_error_msg("%s", s);
132}
133
Francis Laniel8197f012023-12-22 22:02:28 +0100134static 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
142static void *xzalloc(size_t size)
143{
144 void *p = xmalloc(size);
145 memset(p, 0, size);
146 return p;
147}
148
149static 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
Francis Laniel374b77e2023-12-22 22:02:39 +0100157static void *xmemdup(const void *s, int n)
158{
159 return memcpy(xmalloc(n), s, n);
160}
161
Francis Laniel8197f012023-12-22 22:02:28 +0100162#define xstrdup strdup
163#define xstrndup strndup
164
165static 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. */
171static 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
185static 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
200static 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
211static 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
Francis Laniel74e42542023-12-22 22:02:33 +0100222/**
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 */
230static 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
Francis Laniel8197f012023-12-22 22:02:28 +0100239struct in_str;
240static int u_boot_cli_readline(struct in_str *i);
241
242struct in_str;
243static int u_boot_cli_readline(struct in_str *i);
244
245/*
246 * BusyBox globals which are needed for hush.
247 */
248static uint8_t xfunc_error_retval;
249
250static const char defifsvar[] __aligned(1) = "IFS= \t\n";
251#define defifs (defifsvar + 4)
252
Francis Laniel9a068372023-12-22 22:02:32 +0100253/* This define is used to check if exit command was called. */
254#define EXIT_RET_CODE -2
255
Francis Laniel8197f012023-12-22 22:02:28 +0100256/*
257 * This define is used for changes that need be done directly in the upstream
258 * sources still. Ideally, its use should be minimized as much as possible.
259 */
260#define __U_BOOT__
261
262/*
263 *
264 * +-- Include of the upstream sources --+ *
265 * V V
266 */
267#include "cli_hush_upstream.c"
268/*
269 * A A
270 * +-- Include of the upstream sources --+ *
271 *
272 */
273
274int u_boot_hush_start_modern(void)
275{
276 INIT_G();
277 return 0;
278}
279
280static int u_boot_cli_readline(struct in_str *i)
281{
282 char *prompt;
283 char __maybe_unused *ps_prompt = NULL;
284
285 if (!G.promptmode)
286 prompt = CONFIG_SYS_PROMPT;
287#ifdef CONFIG_SYS_PROMPT_HUSH_PS2
288 else
289 prompt = CONFIG_SYS_PROMPT_HUSH_PS2;
290#else
291 /* TODO: default value? */
292 #error "SYS_PROMPT_HUSH_PS2 is not defined!"
293#endif
294
295 if (CONFIG_IS_ENABLED(CMDLINE_PS_SUPPORT)) {
296 if (!G.promptmode)
297 ps_prompt = env_get("PS1");
298 else
299 ps_prompt = env_get("PS2");
300
301 if (ps_prompt)
302 prompt = ps_prompt;
303 }
304
305 return cli_readline(prompt);
306}