mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-26 21:54:37 +08:00
874be948de
This commit adds the following hush busybox upstream commits: 23da5c4b716b ("hush: do not exit interactive shell on some redirection errors") 14e28c18ca1a ("hush: fix "exec 3>FILE" aborting if 3 is exactly the next free fd") 6c38d0e9da2d ("hush: avoid duplicate fcntl(F_SETFD, FD_CLOEXEC) during init") 758b21402abc ("hush: detect when terminating "done"/"fi" is missing") 2639f3bc72ac ("hush: set G.ifs sooner (prevents segfault)") Adding specific ifdef and endif guard was needed for 2639f3bc72ac. Signed-off-by: Francis Laniel <francis.laniel@amarulasolutions.com>
324 lines
6.8 KiB
C
324 lines
6.8 KiB
C
// 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.37.0.git23da5c4b716b"
|
|
|
|
/*
|
|
* 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);
|
|
}
|