blob: 34278fdca2f24d553bea1bcdd9ca4af46d52faec [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
36/* No MMU in U-Boot */
37#define BB_MMU 0
38#define USE_FOR_NOMMU(...) __VA_ARGS__
39#define USE_FOR_MMU(...)
40
41/*
42 * Size-saving "small" ints (arch-dependent)
43 */
44#if CONFIG_IS_ENABLED(X86) || CONFIG_IS_ENABLED(X86_64) || CONFIG_IS_ENABLED(MIPS)
45/* add other arches which benefit from this... */
46typedef signed char smallint;
47typedef unsigned char smalluint;
48#else
49/* for arches where byte accesses generate larger code: */
50typedef int smallint;
51typedef unsigned smalluint;
52#endif
53
54/*
55 * Alignment defines used by BusyBox.
56 */
57#define ALIGN1 __attribute__((aligned(1)))
58#define ALIGN2 __attribute__((aligned(2)))
59#define ALIGN4 __attribute__((aligned(4)))
60#define ALIGN8 __attribute__((aligned(8)))
61#define ALIGN_PTR __attribute__((aligned(sizeof(void*))))
62
63/*
64 * Miscellaneous compiler/platform defines.
65 */
66#define FAST_FUNC /* not used in U-Boot */
67#define UNUSED_PARAM __always_unused
68#define ALWAYS_INLINE __always_inline
69#define NOINLINE noinline
70
71/*
72 * Defines to provide equivalents to what libc/BusyBox defines.
73 */
74#define EOF (-1)
75#define EXIT_SUCCESS 0
76#define EXIT_FAILURE 1
77
78/*
79 * Stubs to provide libc/BusyBox functions based on U-Boot equivalents where it
80 * makes sense.
81 */
82#define utoa simple_itoa
83
84static void __noreturn xfunc_die(void)
85{
86 panic("HUSH died!");
87}
88
89#define bb_error_msg_and_die(format, ...) do { \
90panic("HUSH: " format, __VA_ARGS__); \
91} while (0);
92
93#define bb_simple_error_msg_and_die(msg) do { \
94panic_str("HUSH: " msg); \
95} while (0);
96
97/* fdprintf() is used for debug output. */
98static int __maybe_unused fdprintf(int fd, const char *format, ...)
99{
100 va_list args;
101 uint i;
102
103 assert(fd == 2);
104
105 va_start(args, format);
106 i = vprintf(format, args);
107 va_end(args);
108
109 return i;
110}
111
112static void bb_verror_msg(const char *s, va_list p, const char* strerr)
113{
114 /* TODO: what to do with strerr arg? */
115 vprintf(s, p);
116}
117
118static void bb_error_msg(const char *s, ...)
119{
120 va_list p;
121
122 va_start(p, s);
123 bb_verror_msg(s, p, NULL);
124 va_end(p);
125}
126
127static void *xmalloc(size_t size)
128{
129 void *p = NULL;
130 if (!(p = malloc(size)))
131 panic("out of memory");
132 return p;
133}
134
135static void *xzalloc(size_t size)
136{
137 void *p = xmalloc(size);
138 memset(p, 0, size);
139 return p;
140}
141
142static void *xrealloc(void *ptr, size_t size)
143{
144 void *p = NULL;
145 if (!(p = realloc(ptr, size)))
146 panic("out of memory");
147 return p;
148}
149
150#define xstrdup strdup
151#define xstrndup strndup
152
153static void *mempcpy(void *dest, const void *src, size_t len)
154{
155 return memcpy(dest, src, len) + len;
156}
157
158/* Like strcpy but can copy overlapping strings. */
159static void overlapping_strcpy(char *dst, const char *src)
160{
161 /*
162 * Cheap optimization for dst == src case -
163 * better to have it here than in many callers.
164 */
165 if (dst != src) {
166 while ((*dst = *src) != '\0') {
167 dst++;
168 src++;
169 }
170 }
171}
172
173static char* skip_whitespace(const char *s)
174{
175 /*
176 * In POSIX/C locale (the only locale we care about: do we REALLY want
177 * to allow Unicode whitespace in, say, .conf files? nuts!)
178 * isspace is only these chars: "\t\n\v\f\r" and space.
179 * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13.
180 * Use that.
181 */
182 while (*s == ' ' || (unsigned char)(*s - 9) <= (13 - 9))
183 s++;
184
185 return (char *) s;
186}
187
188static char* skip_non_whitespace(const char *s)
189{
190 while (*s != '\0' && *s != ' ' && (unsigned char)(*s - 9) > (13 - 9))
191 s++;
192
193 return (char *) s;
194}
195
196#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
197#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
198
199static const char* endofname(const char *name)
200{
201 if (!is_name(*name))
202 return name;
203 while (*++name) {
204 if (!is_in_name(*name))
205 break;
206 }
207 return name;
208}
209
210struct in_str;
211static int u_boot_cli_readline(struct in_str *i);
212
213struct in_str;
214static int u_boot_cli_readline(struct in_str *i);
215
216/*
217 * BusyBox globals which are needed for hush.
218 */
219static uint8_t xfunc_error_retval;
220
221static const char defifsvar[] __aligned(1) = "IFS= \t\n";
222#define defifs (defifsvar + 4)
223
224/*
225 * This define is used for changes that need be done directly in the upstream
226 * sources still. Ideally, its use should be minimized as much as possible.
227 */
228#define __U_BOOT__
229
230/*
231 *
232 * +-- Include of the upstream sources --+ *
233 * V V
234 */
235#include "cli_hush_upstream.c"
236/*
237 * A A
238 * +-- Include of the upstream sources --+ *
239 *
240 */
241
242int u_boot_hush_start_modern(void)
243{
244 INIT_G();
245 return 0;
246}
247
248static int u_boot_cli_readline(struct in_str *i)
249{
250 char *prompt;
251 char __maybe_unused *ps_prompt = NULL;
252
253 if (!G.promptmode)
254 prompt = CONFIG_SYS_PROMPT;
255#ifdef CONFIG_SYS_PROMPT_HUSH_PS2
256 else
257 prompt = CONFIG_SYS_PROMPT_HUSH_PS2;
258#else
259 /* TODO: default value? */
260 #error "SYS_PROMPT_HUSH_PS2 is not defined!"
261#endif
262
263 if (CONFIG_IS_ENABLED(CMDLINE_PS_SUPPORT)) {
264 if (!G.promptmode)
265 ps_prompt = env_get("PS1");
266 else
267 ps_prompt = env_get("PS2");
268
269 if (ps_prompt)
270 prompt = ps_prompt;
271 }
272
273 return cli_readline(prompt);
274}