diff options
Diffstat (limited to 'common/cli_hush_modern.c')
-rw-r--r-- | common/cli_hush_modern.c | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/common/cli_hush_modern.c b/common/cli_hush_modern.c new file mode 100644 index 0000000000..cd88c9de8a --- /dev/null +++ b/common/cli_hush_modern.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * This file defines the compilation unit for the new hush shell version. The + * actual implementation from upstream BusyBox can be found in + * `cli_hush_upstream.c` which is included at the end of this file. + * + * This "wrapper" technique is used to keep the changes to the upstream version + * as minmal as possible. Instead, all defines and redefines necessary are done + * here, outside the upstream sources. This will hopefully make upgrades to + * newer revisions much easier. + * + * Copyright (c) 2021, Harald Seiler, DENX Software Engineering, hws@denx.de + */ + +#include <env.h> +#include <malloc.h> /* malloc, free, realloc*/ +#include <linux/ctype.h> /* isalpha, isdigit */ +#include <console.h> +#include <bootretry.h> +#include <cli.h> +#include <cli_hush.h> +#include <command.h> /* find_cmd */ +#include <asm/global_data.h> + +/* + * BusyBox Version: UPDATE THIS WHEN PULLING NEW UPSTREAM REVISION! + */ +#define BB_VER "1.35.0.git7d1c7d833785" + +/* + * Define hush features by the names used upstream. + */ +#define ENABLE_HUSH_INTERACTIVE 1 +#define ENABLE_FEATURE_EDITING 1 +#define ENABLE_HUSH_IF 1 +#define ENABLE_HUSH_LOOPS 1 +/* No MMU in U-Boot */ +#define BB_MMU 0 +#define USE_FOR_NOMMU(...) __VA_ARGS__ +#define USE_FOR_MMU(...) + +/* + * Size-saving "small" ints (arch-dependent) + */ +#if CONFIG_IS_ENABLED(X86) || CONFIG_IS_ENABLED(X86_64) || CONFIG_IS_ENABLED(MIPS) +/* add other arches which benefit from this... */ +typedef signed char smallint; +typedef unsigned char smalluint; +#else +/* for arches where byte accesses generate larger code: */ +typedef int smallint; +typedef unsigned smalluint; +#endif + +/* + * Alignment defines used by BusyBox. + */ +#define ALIGN1 __attribute__((aligned(1))) +#define ALIGN2 __attribute__((aligned(2))) +#define ALIGN4 __attribute__((aligned(4))) +#define ALIGN8 __attribute__((aligned(8))) +#define ALIGN_PTR __attribute__((aligned(sizeof(void*)))) + +/* + * Miscellaneous compiler/platform defines. + */ +#define FAST_FUNC /* not used in U-Boot */ +#define UNUSED_PARAM __always_unused +#define ALWAYS_INLINE __always_inline +#define NOINLINE noinline + +/* + * Defines to provide equivalents to what libc/BusyBox defines. + */ +#define EOF (-1) +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +/* + * Stubs to provide libc/BusyBox functions based on U-Boot equivalents where it + * makes sense. + */ +#define utoa simple_itoa + +static void __noreturn xfunc_die(void) +{ + panic("HUSH died!"); +} + +#define bb_error_msg_and_die(format, ...) do { \ +panic("HUSH: " format, __VA_ARGS__); \ +} while (0); + +#define bb_simple_error_msg_and_die(msg) do { \ +panic_str("HUSH: " msg); \ +} while (0); + +/* fdprintf() is used for debug output. */ +static int __maybe_unused fdprintf(int fd, const char *format, ...) +{ + va_list args; + uint i; + + assert(fd == 2); + + va_start(args, format); + i = vprintf(format, args); + va_end(args); + + return i; +} + +static void bb_verror_msg(const char *s, va_list p, const char* strerr) +{ + /* TODO: what to do with strerr arg? */ + vprintf(s, p); +} + +static void bb_error_msg(const char *s, ...) +{ + va_list p; + + va_start(p, s); + bb_verror_msg(s, p, NULL); + va_end(p); +} + +static void bb_simple_error_msg(const char *s) +{ + bb_error_msg("%s", s); +} + +static void *xmalloc(size_t size) +{ + void *p = NULL; + if (!(p = malloc(size))) + panic("out of memory"); + return p; +} + +static void *xzalloc(size_t size) +{ + void *p = xmalloc(size); + memset(p, 0, size); + return p; +} + +static void *xrealloc(void *ptr, size_t size) +{ + void *p = NULL; + if (!(p = realloc(ptr, size))) + panic("out of memory"); + return p; +} + +static void *xmemdup(const void *s, int n) +{ + return memcpy(xmalloc(n), s, n); +} + +#define xstrdup strdup +#define xstrndup strndup + +static void *mempcpy(void *dest, const void *src, size_t len) +{ + return memcpy(dest, src, len) + len; +} + +/* Like strcpy but can copy overlapping strings. */ +static void overlapping_strcpy(char *dst, const char *src) +{ + /* + * Cheap optimization for dst == src case - + * better to have it here than in many callers. + */ + if (dst != src) { + while ((*dst = *src) != '\0') { + dst++; + src++; + } + } +} + +static char* skip_whitespace(const char *s) +{ + /* + * In POSIX/C locale (the only locale we care about: do we REALLY want + * to allow Unicode whitespace in, say, .conf files? nuts!) + * isspace is only these chars: "\t\n\v\f\r" and space. + * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13. + * Use that. + */ + while (*s == ' ' || (unsigned char)(*s - 9) <= (13 - 9)) + s++; + + return (char *) s; +} + +static char* skip_non_whitespace(const char *s) +{ + while (*s != '\0' && *s != ' ' && (unsigned char)(*s - 9) > (13 - 9)) + s++; + + return (char *) s; +} + +#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) +#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) + +static const char* endofname(const char *name) +{ + if (!is_name(*name)) + return name; + while (*++name) { + if (!is_in_name(*name)) + break; + } + return name; +} + +/** + * list_size() - returns the number of elements in char ** before NULL. + * + * Argument must contain NULL to signalize its end. + * + * @list The list to count the number of element. + * @return The number of element in list. + */ +static size_t list_size(char **list) +{ + size_t size; + + for (size = 0; list[size] != NULL; size++); + + return size; +} + +static int varcmp(const char *p, const char *q) +{ + int c, d; + + while ((c = *p) == (d = *q)) { + if (c == '\0' || c == '=') + goto out; + p++; + q++; + } + if (c == '=') + c = '\0'; + if (d == '=') + d = '\0'; +out: + return c - d; +} + +struct in_str; +static int u_boot_cli_readline(struct in_str *i); + +struct in_str; +static int u_boot_cli_readline(struct in_str *i); + +/* + * BusyBox globals which are needed for hush. + */ +static uint8_t xfunc_error_retval; + +static const char defifsvar[] __aligned(1) = "IFS= \t\n"; +#define defifs (defifsvar + 4) + +/* This define is used to check if exit command was called. */ +#define EXIT_RET_CODE -2 + +/* + * This define is used for changes that need be done directly in the upstream + * sources still. Ideally, its use should be minimized as much as possible. + */ +#define __U_BOOT__ + +/* + * + * +-- Include of the upstream sources --+ * + * V V + */ +#include "cli_hush_upstream.c" +/* + * A A + * +-- Include of the upstream sources --+ * + * + */ + +int u_boot_hush_start_modern(void) +{ + INIT_G(); + return 0; +} + +static int u_boot_cli_readline(struct in_str *i) +{ + char *prompt; + char __maybe_unused *ps_prompt = NULL; + + if (!G.promptmode) + prompt = CONFIG_SYS_PROMPT; +#ifdef CONFIG_SYS_PROMPT_HUSH_PS2 + else + prompt = CONFIG_SYS_PROMPT_HUSH_PS2; +#else + /* TODO: default value? */ + #error "SYS_PROMPT_HUSH_PS2 is not defined!" +#endif + + if (CONFIG_IS_ENABLED(CMDLINE_PS_SUPPORT)) { + if (!G.promptmode) + ps_prompt = env_get("PS1"); + else + ps_prompt = env_get("PS2"); + + if (ps_prompt) + prompt = ps_prompt; + } + + return cli_readline(prompt); +} |