new file mode 100644
@@ -0,0 +1,274 @@
+// 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_2021_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 <common.h> /* readline */
+#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.34.0.git37460f5daff9"
+
+/*
+ * Define hush features by the names used upstream.
+ */
+#define ENABLE_HUSH_INTERACTIVE 1
+#define ENABLE_FEATURE_EDITING 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 *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;
+}
+
+#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;
+}
+
+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 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_2021(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);
+}
@@ -343,6 +343,7 @@
//usage:#define hush_full_usage "\n\n"
//usage: "Unix shell interpreter"
+#ifndef __U_BOOT__
#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| defined(__APPLE__) \
)
@@ -378,6 +379,7 @@
#else
# define NUM_SCRIPTS 0
#endif
+#endif /* !__U_BOOT__ */
/* So far, all bash compat is controlled by one config option */
/* Separate defines document which part of code implements what */
@@ -421,6 +423,7 @@
# define USE_FOR_MMU(...)
#endif
+#ifndef __U_BOOT__
#include "NUM_APPLETS.h"
#if NUM_APPLETS == 1
/* STANDALONE does not make sense, and won't compile */
@@ -432,6 +435,7 @@
# define IF_FEATURE_SH_STANDALONE(...)
# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
#endif
+#endif /* __U_BOOT__ */
#if !ENABLE_HUSH_INTERACTIVE
# undef ENABLE_FEATURE_EDITING
@@ -477,8 +481,13 @@
#define JOB_STATUS_FORMAT "[%u] %-22s %.40s\n"
#define _SPECIAL_VARS_STR "_*@$!?#-"
+#ifndef __U_BOOT__
#define SPECIAL_VARS_STR ("_*@$!?#-" + 1)
#define NUMERIC_SPECVARS_STR ("_*@$!?#-" + 3)
+#else /* __U_BOOT__ */
+#define SPECIAL_VARS_STR "*@$!?#-"
+#define NUMERIC_SPECVARS_STR "$!?#-"
+#endif /* __U_BOOT__ */
#if BASH_PATTERN_SUBST
/* Support / and // replace ops */
/* Note that // is stored as \ in "encoded" string representation */
@@ -511,6 +520,7 @@ typedef struct nommu_save_t {
} nommu_save_t;
#endif
+
enum {
RES_NONE = 0,
#if ENABLE_HUSH_IF
@@ -594,6 +604,7 @@ typedef struct in_str {
HFILE *file;
} in_str;
+#ifndef __U_BOOT__
/* The descrip member of this structure is only used to make
* debugging output pretty */
static const struct {
@@ -640,9 +651,12 @@ typedef enum redir_type {
HEREDOC_QUOTED = 2,
} redir_type;
+#endif /* !__U_BOOT__ */
struct command {
+#ifndef __U_BOOT__
pid_t pid; /* 0 if exited */
+#endif /* !__U_BOOT__ */
unsigned assignment_cnt; /* how many argv[i] are assignments? */
#if ENABLE_HUSH_LINENO_VAR
unsigned lineno;
@@ -684,6 +698,9 @@ struct command {
* When command is freed, it severs the link
* (sets ->child_func->parent_cmd to NULL).
*/
+#endif
+#ifdef __U_BOOT__
+ int argc; /* number of program arguments */
#endif
char **argv; /* command name and arguments */
/* argv vector may contain variable references (^Cvar^C, ^C0^C etc)
@@ -692,15 +709,23 @@ struct command {
* Example: argv[0]=='.^C*^C.' here: echo .$*.
* References of the form ^C`cmd arg^C are `cmd arg` substitutions.
*/
+#ifndef __U_BOOT__
struct redir_struct *redirects; /* I/O redirections */
+#endif /* !__U_BOOT__ */
};
/* Is there anything in this command at all? */
+#ifndef __U_BOOT__
#define IS_NULL_CMD(cmd) \
(!(cmd)->group && !(cmd)->argv && !(cmd)->redirects)
+#else /* __U_BOOT__ */
+#define IS_NULL_CMD(cmd) \
+ (!(cmd)->group && !(cmd)->argv)
+#endif /* __U_BOOT__ */
struct pipe {
struct pipe *next;
int num_cmds; /* total number of commands in pipe */
+#ifndef __U_BOOT__
int alive_cmds; /* number of commands running (not exited) */
int stopped_cmds; /* number of commands alive, but stopped */
#if ENABLE_HUSH_JOB
@@ -708,6 +733,7 @@ struct pipe {
pid_t pgrp; /* process group ID for the job */
char *cmdtext; /* name of job */
#endif
+#endif /* !__U_BOOT__ */
struct command *cmds; /* array of commands in pipe */
smallint followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
IF_HAS_KEYWORDS(smallint pi_inverted;) /* "! cmd | cmd" */
@@ -731,8 +757,10 @@ struct parse_context {
struct pipe *pipe;
/* last command in pipe (being constructed right now) */
struct command *command;
+#ifndef __U_BOOT__
/* last redirect in command->redirects list */
struct redir_struct *pending_redirect;
+#endif /* !__U_BOOT__ */
o_string word;
#if !BB_MMU
o_string as_string;
@@ -766,19 +794,23 @@ enum {
WORD_IS_KEYWORD = 3,
};
+#ifndef __U_BOOT__
/* On program start, environ points to initial environment.
* putenv adds new pointers into it, unsetenv removes them.
* Neither of these (de)allocates the strings.
* setenv allocates new strings in malloc space and does putenv,
* and thus setenv is unusable (leaky) for shell's purposes */
#define setenv(...) setenv_is_leaky_dont_use()
+#endif /* !__U_BOOT__ */
struct variable {
struct variable *next;
char *varstr; /* points to "name=" portion */
int max_len; /* if > 0, name is part of initial env; else name is malloced */
+#ifndef __U_BOOT__
uint16_t var_nest_level;
smallint flg_export; /* putenv should be done on this var */
smallint flg_read_only;
+#endif /* !__U_BOOT__ */
};
enum {
@@ -850,6 +882,7 @@ enum {
/* "Globals" within this file */
/* Sorted roughly by size (smaller offsets == smaller code) */
struct globals {
+#ifndef __U_BOOT__
/* interactive_fd != 0 means we are an interactive shell.
* If we are, then saved_tty_pgrp can also be != 0, meaning
* that controlling tty is available. With saved_tty_pgrp == 0,
@@ -870,6 +903,10 @@ struct globals {
#else
# define G_interactive_fd 0
#endif
+#else /* __U_BOOT__ */
+# define G_interactive_fd 0
+#endif /* __U_BOOT__ */
+#ifndef __U_BOOT__
#if ENABLE_FEATURE_EDITING
line_input_t *line_input_state;
#endif
@@ -888,8 +925,10 @@ struct globals {
#else
# define G_saved_tty_pgrp 0
#endif
+#endif /* !__U_BOOT__ */
/* How deeply are we in context where "set -e" is ignored */
int errexit_depth;
+#ifndef __U_BOOT__
/* "set -e" rules (do we follow them correctly?):
* Exit if pipe, list, or compound command exits with a non-zero status.
* Shell does not exit if failed command is part of condition in
@@ -915,13 +954,16 @@ struct globals {
#endif
char opt_s;
char opt_c;
+#endif /* !__U_BOOT__ */
#if ENABLE_HUSH_INTERACTIVE
smallint promptmode; /* 0: PS1, 1: PS2 */
#endif
smallint flag_SIGINT;
+#ifndef __U_BOOT__
#if ENABLE_HUSH_LOOPS
smallint flag_break_continue;
#endif
+#endif /* !__U_BOOT__ */
#if ENABLE_HUSH_FUNCTIONS
/* 0: outside of a function (or sourced file)
* -1: inside of a function, ok to use return builtin
@@ -937,6 +979,7 @@ struct globals {
smalluint last_exitcode;
smalluint expand_exitcode;
smalluint last_bg_pid_exitcode;
+#ifndef __U_BOOT__
#if ENABLE_HUSH_SET
/* are global_argv and global_argv[1..n] malloced? (note: not [0]) */
smalluint global_args_malloced;
@@ -947,6 +990,7 @@ struct globals {
#if ENABLE_HUSH_BASH_COMPAT
int dead_job_exitcode; /* for "wait -n" */
#endif
+#endif /* !__U_BOOT__ */
/* how many non-NULL argv's we have. NB: $# + 1 */
int global_argc;
char **global_argv;
@@ -954,19 +998,30 @@ struct globals {
char *argv0_for_re_execing;
#endif
#if ENABLE_HUSH_LOOPS
+#ifndef __U_BOOT__
unsigned depth_break_continue;
+#endif /* !__U_BOOT__ */
unsigned depth_of_loop;
#endif
+#ifndef __U_BOOT__
#if ENABLE_HUSH_GETOPTS
unsigned getopt_count;
#endif
+#endif /* !__U_BOOT__ */
const char *ifs;
+#ifdef __U_BOOT__
+ int flag_repeat;
+ int do_repeat;
+#endif /* __U_BOOT__ */
char *ifs_whitespace; /* = G.ifs or malloced */
+#ifndef __U_BOOT__
const char *cwd;
+#endif /* !__U_BOOT__ */
struct variable *top_var;
char **expanded_assignments;
struct variable **shadowed_vars_pp;
unsigned var_nest_level;
+#ifndef __U_BOOT__
#if ENABLE_HUSH_FUNCTIONS
# if ENABLE_HUSH_LOCAL
unsigned func_nest_level; /* solely to prevent "local v" in non-functions */
@@ -1022,9 +1077,11 @@ struct globals {
int x_mode_fd;
o_string x_mode_buf;
#endif
+#endif /* !__U_BOOT__ */
#if HUSH_DEBUG >= 2
int debug_indent;
#endif
+#ifndef __U_BOOT__
struct sigaction sa;
char optstring_buf[sizeof("eixcs")];
#if BASH_EPOCH_VARS
@@ -1033,19 +1090,35 @@ struct globals {
#if ENABLE_FEATURE_EDITING
char user_input_buf[CONFIG_FEATURE_EDITING_MAX_LEN];
#endif
+#endif /* !__U_BOOT__ */
};
+#ifdef __U_BOOT__
+struct globals *ptr_to_globals;
+#endif /* __U_BOOT__ */
#define G (*ptr_to_globals)
/* Not #defining name to G.name - this quickly gets unwieldy
* (too many defines). Also, I actually prefer to see when a variable
* is global, thus "G." prefix is a useful hint */
+#ifdef __U_BOOT__
+#define SET_PTR_TO_GLOBALS(x) do { \
+ (*(struct globals**)&ptr_to_globals) = (void*)(x); \
+ barrier(); \
+} while (0)
+#define INIT_G() do { \
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+ G.promptmode = 1; \
+} while (0)
+#else /* !__U_BOOT__ */
#define INIT_G() do { \
SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
/* memset(&G.sa, 0, sizeof(G.sa)); */ \
sigfillset(&G.sa.sa_mask); \
G.sa.sa_flags = SA_RESTART; \
} while (0)
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
/* Function prototypes for builtins */
static int builtin_cd(char **argv) FAST_FUNC;
#if ENABLE_HUSH_ECHO
@@ -1245,6 +1318,7 @@ static const struct built_in_command bltins2[] ALIGN_PTR = {
#endif
};
+#endif /* !__U_BOOT__ */
/* Debug printouts.
*/
@@ -1396,7 +1470,11 @@ static void die_if_script(void)
}
}
+#ifdef __U_BOOT__
+static void __maybe_unused msg_and_die_if_script(unsigned lineno, const char *fmt, ...)
+#else /* !__U_BOOT__ */
static void msg_and_die_if_script(unsigned lineno, const char *fmt, ...)
+#endif /* !__U_BOOT__ */
{
va_list p;
@@ -1409,6 +1487,7 @@ static void msg_and_die_if_script(unsigned lineno, const char *fmt, ...)
die_if_script();
}
+#ifndef __U_BOOT__
static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg)
{
if (msg)
@@ -1417,6 +1496,7 @@ static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg)
bb_simple_error_msg("syntax error");
die_if_script();
}
+#endif /* !__U_BOOT__ */
static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg)
{
@@ -1465,13 +1545,16 @@ static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch)
# define syntax_error_unexpected_ch(ch) syntax_error_unexpected_ch(__LINE__, ch)
#endif
-
/* Utility functions
*/
/* Replace each \x with x in place, return ptr past NUL. */
static char *unbackslash(char *src)
{
+#ifdef __U_BOOT__
+ char *dst = src = (char *)strchrnul(src, '\\');
+#else /* !__U_BOOT__ */
char *dst = src = strchrnul(src, '\\');
+#endif /* !__U_BOOT__ */
while (1) {
if (*src == '\\') {
src++;
@@ -1539,6 +1622,7 @@ static char **add_string_to_strings(char **strings, char *add)
v[1] = NULL;
return add_strings_to_strings(strings, v, /*dup:*/ 0);
}
+
#if LEAK_HUNTING
static char **xx_add_string_to_strings(int lineno, char **strings, char *add)
{
@@ -1564,6 +1648,7 @@ static void free_strings(char **strings)
free(strings);
}
+#ifndef __U_BOOT__
static int dup_CLOEXEC(int fd, int avoid_fd)
{
int newfd;
@@ -1749,6 +1834,7 @@ static int fd_in_HFILEs(int fd)
return 0;
}
+#endif /* !__U_BOOT__ */
/* Helpers for setting new $n and restoring them back
*/
@@ -1756,9 +1842,12 @@ typedef struct save_arg_t {
char *sv_argv0;
char **sv_g_argv;
int sv_g_argc;
+#ifndef __U_BOOT__
IF_HUSH_SET(smallint sv_g_malloced;)
+#endif /* !__U_BOOT__ */
} save_arg_t;
+#ifndef __U_BOOT__
static void save_and_replace_G_args(save_arg_t *sv, char **argv)
{
sv->sv_argv0 = argv[0];
@@ -1789,8 +1878,10 @@ static void restore_G_args(save_arg_t *sv, char **argv)
G.global_argc = sv->sv_g_argc;
IF_HUSH_SET(G.global_args_malloced = sv->sv_g_malloced;)
}
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
/* Basic theory of signal handling in shell
* ========================================
* This does not describe what hush does, rather, it is current understanding
@@ -1969,7 +2060,9 @@ static sighandler_t install_sighandler(int sig, sighandler_t handler)
sigaction(sig, &G.sa, &old_sa);
return old_sa.sa_handler;
}
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
static void hush_exit(int exitcode) NORETURN;
static void restore_ttypgrp_and__exit(void) NORETURN;
@@ -2039,7 +2132,9 @@ static void sigexit(int sig)
# define enable_restore_tty_pgrp_on_exit() ((void)0)
#endif
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
static sighandler_t pick_sighandler(unsigned sig)
{
sighandler_t handler = SIG_DFL;
@@ -2066,7 +2161,9 @@ static sighandler_t pick_sighandler(unsigned sig)
}
return handler;
}
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
/* Restores tty foreground process group, and exits. */
static void hush_exit(int exitcode)
{
@@ -2226,6 +2323,7 @@ static const char *get_cwd(int force)
return G.cwd;
}
+#endif /* !__U_BOOT__ */
/*
* Shell and environment variable support
@@ -2263,8 +2361,10 @@ static const char* FAST_FUNC get_local_var_value(const char *name)
if (vpp)
return (*vpp)->varstr + len + 1;
+#ifndef __U_BOOT__
if (strcmp(name, "PPID") == 0)
return utoa(G.root_ppid);
+#endif /* !__U_BOOT__ */
// bash compat: UID? EUID?
#if ENABLE_HUSH_RANDOM_SUPPORT
if (strcmp(name, "RANDOM") == 0)
@@ -2293,6 +2393,7 @@ static const char* FAST_FUNC get_local_var_value(const char *name)
return NULL;
}
+#ifndef __U_BOOT__
#if ENABLE_HUSH_GETOPTS
static void handle_changed_special_names(const char *name, unsigned name_len)
{
@@ -2307,15 +2408,25 @@ static void handle_changed_special_names(const char *name, unsigned name_len)
/* Do not even bother evaluating arguments */
# define handle_changed_special_names(...) ((void)0)
#endif
+#else /* __U_BOOT__ */
+/* Do not even bother evaluating arguments */
+# define handle_changed_special_names(...) ((void)0)
+#endif /* __U_BOOT__ */
/* str holds "NAME=VAL" and is expected to be malloced.
* We take ownership of it.
*/
+#ifndef __U_BOOT__
#define SETFLAG_EXPORT (1 << 0)
#define SETFLAG_UNEXPORT (1 << 1)
#define SETFLAG_MAKE_RO (1 << 2)
+#endif /* !__U_BOOT__ */
#define SETFLAG_VARLVL_SHIFT 3
+#ifndef __U_BOOT__
static int set_local_var(char *str, unsigned flags)
+#else /* __U_BOOT__ */
+int set_local_var_2021(char *str, int flags)
+#endif /* __U_BOOT__ */
{
struct variable **cur_pp;
struct variable *cur;
@@ -2323,7 +2434,9 @@ static int set_local_var(char *str, unsigned flags)
char *eq_sign;
int name_len;
int retval;
+#ifndef __U_BOOT__
unsigned local_lvl = (flags >> SETFLAG_VARLVL_SHIFT);
+#endif /* !__U_BOOT__ */
eq_sign = strchr(str, '=');
if (HUSH_DEBUG && !eq_sign)
@@ -2337,6 +2450,7 @@ static int set_local_var(char *str, unsigned flags)
continue;
}
+#ifndef __U_BOOT__
/* We found an existing var with this name */
if (cur->flg_read_only) {
bb_error_msg("%s: readonly variable", str);
@@ -2389,6 +2503,7 @@ static int set_local_var(char *str, unsigned flags)
}
break;
}
+#endif /* !__U_BOOT__ */
if (strcmp(cur->varstr + name_len, eq_sign + 1) == 0) {
debug_printf_env("assignement '%s' does not change anything\n", str);
@@ -2420,15 +2535,22 @@ static int set_local_var(char *str, unsigned flags)
}
/* Not found or shadowed - create new variable struct */
+#ifndef __U_BOOT__
debug_printf_env("%s: alloc new var '%s'/%u\n", __func__, str, local_lvl);
+#else /* __U_BOOT__ */
+ debug_printf_env("%s: alloc new var '%s'\n", __func__, str);
+#endif /* __U_BOOT__ */
cur = xzalloc(sizeof(*cur));
+#ifndef __U_BOOT__
cur->var_nest_level = local_lvl;
+#endif /* !__U_BOOT__ */
cur->next = *cur_pp;
*cur_pp = cur;
set_str_and_exp:
cur->varstr = str;
exp:
+#ifndef __U_BOOT__
#if !BB_MMU || ENABLE_HUSH_READONLY
if (flags & SETFLAG_MAKE_RO) {
cur->flg_read_only = 1;
@@ -2436,7 +2558,9 @@ static int set_local_var(char *str, unsigned flags)
#endif
if (flags & SETFLAG_EXPORT)
cur->flg_export = 1;
+#endif /* !__U_BOOT__ */
retval = 0;
+#ifndef __U_BOOT__
if (cur->flg_export) {
if (flags & SETFLAG_UNEXPORT) {
cur->flg_export = 0;
@@ -2449,6 +2573,7 @@ static int set_local_var(char *str, unsigned flags)
*/
}
}
+#endif /* !__U_BOOT__ */
free(free_me);
handle_changed_special_names(cur->varstr, name_len - 1);
@@ -2456,6 +2581,7 @@ static int set_local_var(char *str, unsigned flags)
return retval;
}
+#ifndef __U_BOOT__
static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val)
{
char *var = xasprintf("%s=%s", name, val);
@@ -2467,6 +2593,7 @@ static void set_pwd_var(unsigned flag)
{
set_local_var(xasprintf("PWD=%s", get_cwd(/*force:*/ 1)), flag);
}
+#endif /* !__U_BOOT__ */
#if ENABLE_HUSH_UNSET || ENABLE_HUSH_GETOPTS
static int unset_local_var_len(const char *name, int name_len)
@@ -2509,6 +2636,7 @@ static int unset_local_var(const char *name)
#endif
+#ifndef __U_BOOT__
/*
* Helpers for "var1=val1 var2=val2 cmd" feature
*/
@@ -2602,11 +2730,13 @@ static void reinit_unicode_for_hush(void)
}
}
+#endif /* !__U_BOOT__ */
/*
* in_str support (strings, and "strings" read from files).
*/
#if ENABLE_HUSH_INTERACTIVE
+#ifndef __U_BOOT__
/* To test correct lineedit/interactive behavior, type from command line:
* echo $P\
* \
@@ -2639,8 +2769,15 @@ static const char *setup_prompt_string(void)
debug_printf("prompt_str '%s'\n", prompt_str);
return prompt_str;
}
+#endif /* !__U_BOOT__ */
+
+#ifndef __U_BOOT__
static int get_user_input(struct in_str *i)
+#else /* __U_BOOT__ */
+static void get_user_input(struct in_str *i)
+#endif /* __U_BOOT__ */
{
+#ifndef __U_BOOT__
# if ENABLE_FEATURE_EDITING
/* In EDITING case, this function reads next input line,
* saves it in i->p, then returns 1st char of it.
@@ -2716,37 +2853,139 @@ static int get_user_input(struct in_str *i)
}
return r;
# endif
+#else /* __U_BOOT__ */
+ int n;
+ int promptme;
+ static char the_command[CONFIG_SYS_CBSIZE + 1];
+
+ bootretry_reset_cmd_timeout();
+ promptme = 1;
+ n = u_boot_cli_readline(i);
+
+# ifdef CONFIG_BOOT_RETRY_TIME
+ if (n == -2) {
+ puts("\nTimeout waiting for command\n");
+# ifdef CONFIG_RESET_TO_RETRY
+ do_reset(NULL, 0, 0, NULL);
+# else
+# error "This currently only works with CONFIG_RESET_TO_RETRY enabled"
+# endif
+ }
+# endif
+ if (n == -1 ) {
+ G.flag_repeat = 0;
+ promptme = 0;
+ }
+ n = strlen(console_buffer);
+ console_buffer[n] = '\n';
+ console_buffer[n+1]= '\0';
+ if (had_ctrlc())
+ G.flag_repeat = 0;
+ clear_ctrlc();
+ G.do_repeat = 0;
+#ifndef __U_BOOT__
+ if (G.promptmode == 1) {
+#else /* __U_BOOT__ */
+ if (!G.promptmode) {
+#endif /* __U_BOOT__ */
+ if (console_buffer[0] == '\n'&& G.flag_repeat == 0) {
+ strcpy(the_command, console_buffer);
+ }
+ else {
+ if (console_buffer[0] != '\n') {
+ strcpy(the_command, console_buffer);
+ G.flag_repeat = 1;
+ }
+ else {
+ G.do_repeat = 1;
+ }
+ }
+ i->p = the_command;
+ }
+ else {
+ if (console_buffer[0] != '\n') {
+ if (strlen(the_command) + strlen(console_buffer)
+ < CONFIG_SYS_CBSIZE) {
+ n = strlen(the_command);
+#ifdef __U_BOOT__
+ /*
+ * To avoid writing to bad places, we check if
+ * n is greater than 0.
+ * This bug was found by Harald Seiler.
+ */
+ if (n > 0)
+ the_command[n-1] = ' ';
+ strcpy(&the_command[n], console_buffer);
+#else /* !__U_BOOT__ */
+ the_command[n-1] = ' ';
+ strcpy(&the_command[n], console_buffer);
+#endif /* !__U_BOOT__ */
+ }
+ else {
+ the_command[0] = '\n';
+ the_command[1] = '\0';
+ G.flag_repeat = 0;
+ }
+ }
+ if (promptme == 0) {
+ the_command[0] = '\n';
+ the_command[1] = '\0';
+ }
+ i->p = console_buffer;
+ }
+#endif /* __U_BOOT__ */
}
/* This is the magic location that prints prompts
* and gets data back from the user */
static int fgetc_interactive(struct in_str *i)
{
int ch;
+#ifndef __U_BOOT__
/* If it's interactive stdin, get new line. */
if (G_interactive_fd && i->file == G.HFILE_stdin) {
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
/* Returns first char (or EOF), the rest is in i->p[] */
ch = get_user_input(i);
+#else /* __U_BOOT__ */
+ /* Avoid garbage value and make clang happy. */
+ ch = 0;
+ /*
+ * get_user_input() does not return anything when used in
+ * U-Boot.
+ * So, we need to take the read character from i->p[].
+ */
+ get_user_input(i);
+ if (i->p && *i->p) {
+ ch = *i->p++;
+ }
+#endif /* __U_BOOT__ */
G.promptmode = 1; /* PS2 */
debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
+#ifndef __U_BOOT__
} else {
/* Not stdin: script file, sourced file, etc */
do ch = hfgetc(i->file); while (ch == '\0');
}
+#endif /* !__U_BOOT__ */
return ch;
}
#else /* !INTERACTIVE */
+#ifndef __U_BOOT__
static ALWAYS_INLINE int fgetc_interactive(struct in_str *i)
{
int ch;
do ch = hfgetc(i->file); while (ch == '\0');
return ch;
}
+#endif /* !__U_BOOT__ */
#endif /* !INTERACTIVE */
static int i_getch(struct in_str *i)
{
int ch;
+#ifndef __U_BOOT__
if (!i->file) {
/* string-based in_str */
ch = (unsigned char)*i->p;
@@ -2758,6 +2997,7 @@ static int i_getch(struct in_str *i)
return EOF;
}
+#endif /* !__U_BOOT__ */
/* FILE-based in_str */
#if ENABLE_FEATURE_EDITING
@@ -2767,6 +3007,7 @@ static int i_getch(struct in_str *i)
goto out;
}
#endif
+#ifndef __U_BOOT__
/* peek_buf[] is an int array, not char. Can contain EOF. */
ch = i->peek_buf[0];
if (ch != 0) {
@@ -2778,6 +3019,7 @@ static int i_getch(struct in_str *i)
goto out;
}
+#endif /* !__U_BOOT__ */
ch = fgetc_interactive(i);
out:
debug_printf("file_get: got '%c' %d\n", ch, ch);
@@ -2793,6 +3035,7 @@ static int i_getch(struct in_str *i)
static int i_peek(struct in_str *i)
{
+#ifndef __U_BOOT__
int ch;
if (!i->file) {
@@ -2827,6 +3070,11 @@ static int i_peek(struct in_str *i)
i->peek_buf[0] = ch;
/*i->peek_buf[1] = 0; - already is */
return ch;
+#else /* __U_BOOT__ */
+ /* string-based in_str */
+ /* Doesn't report EOF on NUL. None of the callers care. */
+ return (unsigned char)*i->p;
+#endif /* __U_BOOT__ */
}
/* Only ever called if i_peek() was called, and did not return EOF.
@@ -2835,7 +3083,9 @@ static int i_peek(struct in_str *i)
*/
static int i_peek2(struct in_str *i)
{
+#ifndef __U_BOOT__
int ch;
+#endif /* !__U_BOOT__ */
/* There are two cases when i->p[] buffer exists.
* (1) it's a string in_str.
@@ -2846,6 +3096,7 @@ static int i_peek2(struct in_str *i)
if (i->p)
return (unsigned char)i->p[1];
+#ifndef __U_BOOT__
/* Now we know it is a file-based in_str. */
/* peek_buf[] is an int array, not char. Can contain EOF. */
@@ -2859,6 +3110,9 @@ static int i_peek2(struct in_str *i)
debug_printf("file_peek2: got '%c' %d\n", ch, ch);
return ch;
+#else
+ return 0;
+#endif /* __U_BOOT__ */
}
static int i_getch_and_eat_bkslash_nl(struct in_str *input)
@@ -2897,13 +3151,20 @@ static int i_peek_and_eat_bkslash_nl(struct in_str *input)
}
}
+#ifndef __U_BOOT__
static void setup_file_in_str(struct in_str *i, HFILE *fp)
+#else /* __U_BOOT__ */
+static void setup_file_in_str(struct in_str *i)
+#endif /* __U_BOOT__ */
{
memset(i, 0, sizeof(*i));
+#ifndef __U_BOOT__
i->file = fp;
/* i->p = NULL; */
+#endif /* !__U_BOOT__ */
}
+#ifndef __U_BOOT__
static void setup_string_in_str(struct in_str *i, const char *s)
{
memset(i, 0, sizeof(*i));
@@ -2911,6 +3172,7 @@ static void setup_string_in_str(struct in_str *i, const char *s)
i->p = s;
}
+#endif /* !__U_BOOT__ */
/*
* o_string support
@@ -2980,10 +3242,12 @@ static void o_addstr(o_string *o, const char *str)
o_addblock(o, str, strlen(str));
}
+#ifndef __U_BOOT__
static void o_addstr_with_NUL(o_string *o, const char *str)
{
o_addblock(o, str, strlen(str) + 1);
}
+#endif /* !__U_BOOT__ */
#if !BB_MMU
static void nommu_addchr(o_string *o, int ch)
@@ -2995,6 +3259,7 @@ static void nommu_addchr(o_string *o, int ch)
# define nommu_addchr(o, str) ((void)0)
#endif
+#ifndef __U_BOOT__
#if ENABLE_HUSH_MODE_X
static void x_mode_addchr(int ch)
{
@@ -3025,6 +3290,7 @@ static void x_mode_flush(void)
G.x_mode_buf.length = 0;
}
#endif
+#endif /* !__U_BOOT__ */
/*
* HUSH_BRACE_EXPANSION code needs corresponding quoting on variable expansion side.
@@ -3156,7 +3422,11 @@ static void debug_print_list(const char *prefix, o_string *o, int n)
if (n) {
const char *p = o->data + (int)(uintptr_t)list[n - 1] + string_start;
indent();
+#ifndef __U_BOOT__
fdprintf(2, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data));
+#else /* __U_BOOT__ */
+ printf(" total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data));
+#endif /* __U_BOOT__ */
}
}
#else
@@ -3216,6 +3486,7 @@ static int o_get_last_ptr(o_string *o, int n)
return ((int)(uintptr_t)list[n-1]) + string_start;
}
+#ifndef __U_BOOT__
/*
* Globbing routines.
*
@@ -3524,12 +3795,14 @@ static int perform_glob(o_string *o, int n)
return n;
}
+#endif /* !__U_BOOT__ */
#endif /* !HUSH_BRACE_EXPANSION */
/* If o->o_expflags & EXP_FLAG_GLOB, glob the string so far remembered.
* Otherwise, just finish current list[] and start new */
static int o_save_ptr(o_string *o, int n)
{
+#ifndef __U_BOOT__
if (o->o_expflags & EXP_FLAG_GLOB) {
/* If o->has_empty_slot, list[n] was already globbed
* (if it was requested back then when it was filled)
@@ -3537,6 +3810,7 @@ static int o_save_ptr(o_string *o, int n)
if (!o->has_empty_slot)
return perform_glob(o, n); /* o_save_ptr_helper is inside */
}
+#endif /* !__U_BOOT__ */
return o_save_ptr_helper(o, n);
}
@@ -3567,10 +3841,14 @@ static struct pipe *free_pipe(struct pipe *pi)
struct pipe *next;
int i;
+#ifndef __U_BOOT__
debug_printf_clean("free_pipe (pid %d)\n", getpid());
+#endif /* !__U_BOOT__ */
for (i = 0; i < pi->num_cmds; i++) {
struct command *command;
+#ifndef __U_BOOT__
struct redir_struct *r, *rnext;
+#endif /* !__U_BOOT__ */
command = &pi->cmds[i];
debug_printf_clean(" command %d:\n", i);
@@ -3605,6 +3883,7 @@ static struct pipe *free_pipe(struct pipe *pi)
free(command->group_as_string);
//command->group_as_string = NULL;
#endif
+#ifndef __U_BOOT__
for (r = command->redirects; r; r = rnext) {
debug_printf_clean(" redirect %d%s",
r->rd_fd, redir_table[r->rd_type].descrip);
@@ -3619,13 +3898,16 @@ static struct pipe *free_pipe(struct pipe *pi)
free(r);
}
//command->redirects = NULL;
+#endif /* !__U_BOOT__ */
}
free(pi->cmds); /* children are an array, they get freed all at once */
//pi->cmds = NULL;
+#ifndef __U_BOOT__
#if ENABLE_HUSH_JOB
free(pi->cmdtext);
//pi->cmdtext = NULL;
#endif
+#endif /* !__U_BOOT__ */
next = pi->next;
free(pi);
@@ -3655,6 +3937,7 @@ static void debug_print_tree(struct pipe *pi, int lvl)
[PIPE_OR ] = "OR" ,
[PIPE_BG ] = "BG" ,
};
+#ifndef __U_BOOT__
static const char *RES[] = {
[RES_NONE ] = "NONE" ,
# if ENABLE_HUSH_IF
@@ -3684,6 +3967,7 @@ static void debug_print_tree(struct pipe *pi, int lvl)
[RES_XXXX ] = "XXXX" ,
[RES_SNTX ] = "SNTX" ,
};
+#endif /* !__U_BOOT__ */
static const char *const CMDTYPE[] = {
"{}",
"()",
@@ -3701,8 +3985,10 @@ static void debug_print_tree(struct pipe *pi, int lvl)
lvl*2, "",
pin,
pi->num_cmds,
+#ifdef __U_BOOT__
(IF_HAS_KEYWORDS(pi->pi_inverted ? "! " :) ""),
RES[pi->res_word],
+#endif /* !__U_BOOT__ */
pi->followup, PIPE[pi->followup]
);
prn = 0;
@@ -3734,8 +4020,10 @@ static void debug_print_tree(struct pipe *pi, int lvl)
fdprintf(2, " '%s'", *argv);
argv++;
}
+#ifndef __U_BOOT__
if (command->redirects)
fdprintf(2, " {redir}");
+#endif /* __U_BOOT__ */
fdprintf(2, "\n");
prn++;
}
@@ -3869,8 +4157,13 @@ static void done_pipe(struct parse_context *ctx, pipe_style type)
) {
struct pipe *new_p;
debug_printf_parse("done_pipe: adding new pipe: "
+#ifndef __U_BOOT__
"not_null:%d ctx->ctx_res_w:%d\n",
not_null, ctx->ctx_res_w);
+#else /* __U_BOOT__ */
+ "not_null:%d\n",
+ not_null);
+#endif /* __U_BOOT__ */
new_p = new_pipe();
ctx->pipe->next = new_p;
ctx->pipe = new_p;
@@ -4096,6 +4389,7 @@ static int done_word(struct parse_context *ctx)
return 0;
}
+#ifndef __U_BOOT__
if (ctx->pending_redirect) {
/* We do not glob in e.g. >*.tmp case. bash seems to glob here
* only if run as "bash", not "sh" */
@@ -4137,6 +4431,7 @@ static int done_word(struct parse_context *ctx)
debug_printf_parse("word stored in rd_filename: '%s'\n", ctx->word.data);
ctx->pending_redirect = NULL;
} else {
+#endif /* !__U_BOOT__ */
#if HAS_KEYWORDS
# if ENABLE_HUSH_CASE
if (ctx->ctx_dsemicolon
@@ -4247,8 +4542,14 @@ static int done_word(struct parse_context *ctx)
}
debug_printf_parse("ctx->is_assignment='%s'\n", assignment_flag[ctx->is_assignment]);
command->argv = add_string_to_strings(command->argv, xstrdup(ctx->word.data));
+#ifdef __U_BOOT__
+ command->argc++;
+#endif /* __U_BOOT__ */
debug_print_strings("word appended to argv", command->argv);
+
+#ifndef __U_BOOT__
}
+#endif /* !__U_BOOT__ */
#if ENABLE_HUSH_LOOPS
if (ctx->ctx_res_w == RES_FOR) {
@@ -4280,6 +4581,7 @@ static int done_word(struct parse_context *ctx)
}
+#ifndef __U_BOOT__
/* Peek ahead in the input to find out if we have a "&n" construct,
* as in "2>&1", that represents duplicating a file descriptor.
* Return:
@@ -4463,7 +4765,11 @@ static char *fetch_till_str(o_string *as_string,
nommu_addchr(as_string, ch);
if (ch == '\n' || ch == EOF) {
check_heredoc_end:
+#ifndef __U_BOOT__
if ((heredoc_flags & HEREDOC_QUOTED) || prev != '\\') {
+#else /* __U_BOOT__ */
+ if (prev != '\\') {
+#endif
/* End-of-line, and not a line continuation */
if (strcmp(heredoc.data + past_EOL, word) == 0) {
heredoc.data[past_EOL] = '\0';
@@ -4483,7 +4789,11 @@ static char *fetch_till_str(o_string *as_string,
ch = i_getch(input);
if (ch != EOF)
nommu_addchr(as_string, ch);
+#ifndef __U_BOOT__
} while ((heredoc_flags & HEREDOC_SKIPTABS) && ch == '\t');
+#else /* __U_BOOT__ */
+ } while (ch == '\t');
+#endif
/* If this immediately ended the line,
* go back to end-of-line checks.
*/
@@ -4520,6 +4830,7 @@ static char *fetch_till_str(o_string *as_string,
prev = ch;
}
}
+#endif /* !__U_BOOT__ */
/* Look at entire parse tree for not-yet-loaded REDIRECT_HEREDOCs
* and load them all. There should be exactly heredoc_cnt of them.
@@ -4539,10 +4850,13 @@ static int fetch_heredocs(o_string *as_string, struct pipe *pi, int heredoc_cnt,
cmd->argv ? cmd->argv[0] : "NONE"
);
for (i = 0; i < pi->num_cmds; i++) {
+#ifndef __U_BOOT__
struct redir_struct *redir = cmd->redirects;
+#endif /* !__U_BOOT__ */
debug_printf_heredoc("fetch_heredocs: %d cmd argv0:'%s'\n",
i, cmd->argv ? cmd->argv[0] : "NONE");
+#ifndef __U_BOOT__
while (redir) {
if (redir->rd_type == REDIRECT_HEREDOC) {
char *p;
@@ -4561,6 +4875,7 @@ static int fetch_heredocs(o_string *as_string, struct pipe *pi, int heredoc_cnt,
}
redir = redir->next;
}
+#endif /* !__U_BOOT__ */
if (cmd->group) {
//bb_error_msg("%s:%u heredoc_cnt:%d", __func__, __LINE__, heredoc_cnt);
heredoc_cnt = fetch_heredocs(as_string, cmd->group, heredoc_cnt, input);
@@ -4651,13 +4966,17 @@ static int parse_group(struct parse_context *ctx,
}
#endif
+#ifndef __U_BOOT__
IF_HUSH_FUNCTIONS(skip:)
+#endif /* !__U_BOOT__ */
endch = '}';
if (ch == '(') {
endch = ')';
+#ifndef __U_BOOT__
IF_HUSH_FUNCTIONS(if (command->cmd_type != CMD_FUNCDEF))
command->cmd_type = CMD_SUBSHELL;
+#endif /* !__U_BOOT__ */
} else {
/* bash does not allow "{echo...", requires whitespace */
ch = i_peek(input);
@@ -4725,6 +5044,7 @@ static int parse_group(struct parse_context *ctx,
#undef as_string
}
+#ifndef __U_BOOT__
#if ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS
/* Subroutines for copying $(...) and `...` things */
/* '...' */
@@ -4754,6 +5074,7 @@ static int add_till_single_quote_dquoted(o_string *dest, struct in_str *input)
o_addqchr(dest, ch);
}
}
+
/* "...\"...`..`...." - do we need to handle "...$(..)..." too? */
static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote);
static int add_till_double_quote(o_string *dest, struct in_str *input)
@@ -4780,6 +5101,8 @@ static int add_till_double_quote(o_string *dest, struct in_str *input)
//if (ch == '$') ...
}
}
+
+
/* Process `cmd` - copy contents until "`" is seen. Complicated by
* \` quoting.
* "Within the backquoted style of command substitution, backslash
@@ -5014,6 +5337,7 @@ static int parse_dollar_squote(o_string *as_string, o_string *dest, struct in_st
#else
# #define parse_dollar_squote(as_string, dest, input) 0
#endif /* BASH_DOLLAR_SQUOTE */
+#endif /* !__U_BOOT__ */
/* Return code: 0 for OK, 1 for syntax error */
#if BB_MMU
@@ -5056,8 +5380,10 @@ static int parse_dollar(o_string *as_string,
o_addchr(dest, ch | quote_mask);
o_addchr(dest, SPECIAL_VAR_SYMBOL);
} else switch (ch) {
+#ifndef __U_BOOT__
case '$': /* pid */
case '!': /* last bg pid */
+#endif /* !__U_BOOT__ */
case '?': /* last exit code */
case '#': /* number of args */
case '*': /* args */
@@ -5132,7 +5458,9 @@ static int parse_dollar(o_string *as_string,
break;
if (!isalnum(ch) && ch != '_') {
unsigned end_ch;
+#ifndef __U_BOOT__
unsigned char last_ch;
+#endif /* !__U_BOOT__ */
/* handle parameter expansions
* http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02
*/
@@ -5151,6 +5479,7 @@ static int parse_dollar(o_string *as_string,
eat_until_closing:
/* Eat everything until closing '}' (or ':') */
end_ch = '}';
+#ifndef __U_BOOT__
if (BASH_SUBSTR
&& ch == ':'
&& !strchr(MINUS_PLUS_EQUAL_QUESTION, i_peek(input))
@@ -5169,6 +5498,7 @@ static int parse_dollar(o_string *as_string,
}
end_ch = '}' * 0x100 + '/';
}
+#endif /* !__U_BOOT__ */
o_addchr(dest, ch);
/* The pattern can't be empty.
* IOW: if the first char after "${v//" is a slash,
@@ -5179,21 +5509,28 @@ static int parse_dollar(o_string *as_string,
if (i_peek(input) == '/') {
o_addchr(dest, i_getch(input));
}
+#ifndef __U_BOOT__
again:
+#endif /* !__U_BOOT__ */
if (!BB_MMU)
pos = dest->length;
#if ENABLE_HUSH_DOLLAR_OPS
+#ifndef __U_BOOT__
last_ch = add_till_closing_bracket(dest, input, end_ch);
if (last_ch == 0) /* error? */
return 0;
+#endif /* !__U_BOOT__ */
#else
# error Simple code to only allow ${var} is not implemented
#endif
if (as_string) {
o_addstr(as_string, dest->data + pos);
+#ifndef __U_BOOT__
o_addchr(as_string, last_ch);
+#endif /* !__U_BOOT__ */
}
+#ifndef __U_BOOT__
if ((BASH_SUBSTR || BASH_PATTERN_SUBST)
&& (end_ch & 0xff00)
) {
@@ -5212,6 +5549,7 @@ static int parse_dollar(o_string *as_string,
o_addstr(dest, "999999999");
} /* else: it's ${var/[/]pattern} */
}
+#endif /* !__U_BOOT__ */
break;
}
len_single_ch = 0; /* it can't be ${#C} op */
@@ -5415,8 +5753,10 @@ static struct pipe *parse_stream(char **pstring,
const char *is_special;
int ch;
int next;
+#ifndef __U_BOOT__
int redir_fd;
redir_type redir_style;
+#endif /* !__U_BOOT__ */
ch = i_getch(input);
debug_printf_parse(": ch=%c (%d) escape=%d\n",
@@ -5506,8 +5846,10 @@ static struct pipe *parse_stream(char **pstring,
if (ch == '\'') {
ctx.word.has_quoted_part = 1;
next = i_getch(input);
+#ifndef __U_BOOT__
if (next == '\'' && !ctx.pending_redirect)
goto insert_empty_quoted_str_marker;
+#endif /* !__U_BOOT__ */
ch = next;
while (1) {
@@ -5534,7 +5876,11 @@ static struct pipe *parse_stream(char **pstring,
next = i_peek_and_eat_bkslash_nl(input);
is_special = "{}<>&|();#" /* special outside of "str" */
+#ifndef __U_BOOT__
"$\"" IF_HUSH_TICK("`") /* always special */
+#else /* __U_BOOT__ */
+ "$\""
+#endif /* __U_BOOT__ */
SPECIAL_VAR_SYMBOL_STR;
#if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
if (ctx.command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB) {
@@ -5649,7 +5995,11 @@ static struct pipe *parse_stream(char **pstring,
* } is an ordinary char in this case, even inside { cmd; }
* Pathological example: { ""}; } should exec "}" cmd
*/
+#ifndef __U_BOOT__
if (ch == '}') {
+#else /* __U_BOOT__ */
+ if (ch == '}' || ch == ')') {
+#endif /* __U_BOOT__ */
if (ctx.word.length != 0 /* word} */
|| ctx.word.has_quoted_part /* ""} */
) {
@@ -5725,6 +6075,7 @@ static struct pipe *parse_stream(char **pstring,
/* Catch <, > before deciding whether this word is
* an assignment. a=1 2>z b=2: b=2 is still assignment */
switch (ch) {
+#ifndef __U_BOOT__
case '>':
redir_fd = redirect_opt_num(&ctx.word);
if (done_word(&ctx)) {
@@ -5771,6 +6122,7 @@ static struct pipe *parse_stream(char **pstring,
if (parse_redirect(&ctx, redir_fd, redir_style, input))
goto parse_error_exitcode1;
continue; /* get next char */
+#endif /* !__U_BOOT__ */
case '#':
if (ctx.word.length == 0 && !ctx.word.has_quoted_part) {
/* skip "#comment" */
@@ -5798,8 +6150,10 @@ static struct pipe *parse_stream(char **pstring,
skip_end_trigger:
if (ctx.is_assignment == MAYBE_ASSIGNMENT
+#ifndef __U_BOOT__
/* check that we are not in word in "a=1 2>word b=1": */
&& !ctx.pending_redirect
+#endif /* !__U_BOOT__ */
) {
/* ch is a special char and thus this word
* cannot be an assignment */
@@ -5821,8 +6175,10 @@ static struct pipe *parse_stream(char **pstring,
o_addchr(&ctx.word, ch);
continue; /* get next char */
case '$':
+#ifndef __U_BOOT__
if (parse_dollar_squote(&ctx.as_string, &ctx.word, input))
continue; /* get next char */
+#endif /* !__U_BOOT__ */
if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) {
debug_printf_parse("parse_stream parse error: "
"parse_dollar returned 0 (error)\n");
@@ -5831,9 +6187,15 @@ static struct pipe *parse_stream(char **pstring,
continue; /* get next char */
case '"':
ctx.word.has_quoted_part = 1;
+#ifndef __U_BOOT__
if (next == '"' && !ctx.pending_redirect) {
+#else /* __U_BOOT__ */
+ if (next == '"') {
+#endif /* __U_BOOT__ */
i_getch(input); /* eat second " */
+#ifndef __U_BOOT__
insert_empty_quoted_str_marker:
+#endif /* !__U_BOOT__ */
nommu_addchr(&ctx.as_string, next);
o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
o_addchr(&ctx.word, SPECIAL_VAR_SYMBOL);
@@ -6140,6 +6502,7 @@ static int expand_on_ifs(o_string *output, int n, const char *str)
return n;
}
+#ifndef __U_BOOT__
/* Helper to expand $((...)) and heredoc body. These act as if
* they are in double quotes, with the exception that they are not :).
* Just the rules are similar: "expand only $var and `cmd`"
@@ -6440,7 +6803,9 @@ static int encode_then_append_var_plusminus(o_string *output, int n,
o_free(&dest);
return n;
}
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
#if ENABLE_FEATURE_SH_MATH
static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
{
@@ -6461,7 +6826,9 @@ static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
return res;
}
#endif
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
#if BASH_PATTERN_SUBST
/* ${var/[/]pattern[/repl]} helpers */
static char *strstr_pattern(char *val, const char *pattern, int *size)
@@ -6529,6 +6896,7 @@ static char *replace_pattern(char *val, const char *pattern, const char *repl, c
return result;
}
#endif /* BASH_PATTERN_SUBST */
+#endif /* !__U_BOOT__ */
static int append_str_maybe_ifs_split(o_string *output, int n,
int first_ch, const char *val)
@@ -6593,6 +6961,7 @@ static NOINLINE int expand_one_var(o_string *output, int n,
exp_saveptr = var+1 + strcspn(var+1, VAR_ENCODED_SUBST_OPS);
}
exp_op = exp_save = *exp_saveptr;
+#ifndef __U_BOOT__
if (exp_op) {
exp_word = exp_saveptr + 1;
if (exp_op == ':') {
@@ -6608,29 +6977,37 @@ static NOINLINE int expand_one_var(o_string *output, int n,
}
*exp_saveptr = '\0';
} /* else: it's not an expansion op, but bare ${var} */
+#endif /* !__U_BOOT__ */
}
/* Look up the variable in question */
if (isdigit(var[0])) {
/* parse_dollar should have vetted var for us */
+#ifndef __U_BOOT__
int nn = xatoi_positive(var);
+#else /* __U_BOOT__ */
+ int nn = simple_strtoul(var, NULL, 10);
+#endif /* __U_BOOT__ */
if (nn < G.global_argc)
val = G.global_argv[nn];
/* else val remains NULL: $N with too big N */
} else {
switch (var[0]) {
+#ifndef __U_BOOT__
case '$': /* pid */
val = utoa(G.root_pid);
break;
case '!': /* bg pid */
val = G.last_bg_pid ? utoa(G.last_bg_pid) : "";
break;
+#endif /* !__U_BOOT__ */
case '?': /* exitcode */
val = utoa(G.last_exitcode);
break;
case '#': /* argc */
val = utoa(G.global_argc ? G.global_argc-1 : 0);
break;
+#ifndef __U_BOOT__
case '-': { /* active options */
/* Check set_mode() to see what option chars we support */
char *cp;
@@ -6652,11 +7029,13 @@ static NOINLINE int expand_one_var(o_string *output, int n,
*cp = '\0';
break;
}
+#endif /* !__U_BOOT__ */
default:
val = get_local_var_value(var);
}
}
+#ifndef __U_BOOT__
/* Handle any expansions */
if (exp_op == 'L') {
reinit_unicode_for_hush();
@@ -6936,6 +7315,7 @@ static NOINLINE int expand_one_var(o_string *output, int n,
*exp_saveptr = exp_save;
} /* if (exp_op) */
+#endif /* !__U_BOOT__ */
arg[0] = arg0;
*pp = p;
@@ -7248,6 +7628,7 @@ static char* expand_strvec_to_string(char **argv)
}
#endif
+#ifndef __U_BOOT__
static char **expand_assignments(char **argv, int count)
{
int i;
@@ -7289,7 +7670,9 @@ static void switch_off_special_sigs(unsigned mask)
install_sighandler(sig, SIG_DFL);
}
}
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
#if BB_MMU
/* never called */
void re_execute_shell(char ***to_free, const char *s,
@@ -7479,6 +7862,7 @@ static void re_execute_shell(char ***to_free, const char *s,
}
#endif /* !BB_MMU */
+#endif /* !__U_BOOT__ */
static int run_and_free_list(struct pipe *pi);
@@ -7537,6 +7921,7 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger)
}
}
+#ifndef __U_BOOT__
static void parse_and_run_string(const char *s)
{
struct in_str input;
@@ -7546,18 +7931,30 @@ static void parse_and_run_string(const char *s)
parse_and_run_stream(&input, '\0');
//IF_HUSH_LINENO_VAR(G.parse_lineno = sv;)
}
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
static void parse_and_run_file(HFILE *fp)
+#else /* __U_BOOT__ */
+void parse_and_run_file(void)
+#endif /* __U_BOOT__ */
{
struct in_str input;
+#ifndef __U_BOOT__
IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;)
IF_HUSH_LINENO_VAR(G.parse_lineno = 1;)
setup_file_in_str(&input, fp);
+#else /* __U_BOOT__ */
+ setup_file_in_str(&input);
+#endif /* __U_BOOT__ */
parse_and_run_stream(&input, ';');
+#ifndef __U_BOOT__
IF_HUSH_LINENO_VAR(G.parse_lineno = sv;)
+#endif /* !__U_BOOT__ */
}
+#ifndef __U_BOOT__
#if ENABLE_HUSH_TICK
static int generate_stream_from_string(const char *s, pid_t *pid_p)
{
@@ -8163,7 +8560,9 @@ static const char * FAST_FUNC get_builtin_name(int i)
return NULL;
}
#endif
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
static void remove_nested_vars(void)
{
struct variable *cur;
@@ -8215,6 +8614,7 @@ static void leave_var_nest_level(void)
remove_nested_vars();
}
+#endif /* __U_BOOT__ */
#if ENABLE_HUSH_FUNCTIONS
static struct function **find_function_slot(const char *name)
@@ -8399,6 +8799,7 @@ static int run_function(const struct function *funcp, char **argv)
#endif /* ENABLE_HUSH_FUNCTIONS */
+#ifndef __U_BOOT__
#if BB_MMU
#define exec_builtin(to_free, x, argv) \
exec_builtin(x, argv)
@@ -8431,8 +8832,10 @@ static void exec_builtin(char ***to_free,
argv);
#endif
}
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
static void execvp_or_die(char **argv) NORETURN;
static void execvp_or_die(char **argv)
{
@@ -8514,7 +8917,9 @@ static void dump_cmd_in_x_mode(char **argv)
#else
# define dump_cmd_in_x_mode(argv) ((void)0)
#endif
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
#if ENABLE_HUSH_COMMAND
static void if_command_vV_print_and_exit(char opt_vV, char *cmd, const char *explanation)
{
@@ -8540,6 +8945,7 @@ static void if_command_vV_print_and_exit(char opt_vV, char *cmd, const char *exp
#else
# define if_command_vV_print_and_exit(a,b,c) ((void)0)
#endif
+#endif /* !__U_BOOT__ */
#if BB_MMU
#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \
@@ -8548,6 +8954,7 @@ static void if_command_vV_print_and_exit(char opt_vV, char *cmd, const char *exp
pseudo_exec(command, argv_expanded)
#endif
+#ifndef __U_BOOT__
/* Called after [v]fork() in run_pipe, or from builtin_exec.
* Never returns.
* Don't exit() here. If you don't exec, use _exit instead.
@@ -9186,18 +9593,34 @@ static int redirect_and_varexp_helper(
return setup_redirects(command, sqp);
}
+#endif /* !__U_BOOT__ */
+
static NOINLINE int run_pipe(struct pipe *pi)
{
static const char *const null_ptr = NULL;
int cmd_no;
+#ifndef __U_BOOT__
int next_infd;
+#endif /* !__U_BOOT__ */
struct command *command;
char **argv_expanded;
char **argv;
+#ifndef __U_BOOT__
struct squirrel *squirrel = NULL;
+#endif /* !__U_BOOT__ */
int rcode;
+#ifdef __U_BOOT__
+ /*
+ * Set rcode here to avoid returning a garbage value in the middle of
+ * the function.
+ * Also, if an error occurs, rcode value would be changed and last
+ * return will signal the error.
+ */
+ rcode = 0;
+#endif /* __U_BOOT__ */
+
debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds);
debug_enter();
@@ -9230,11 +9653,14 @@ static NOINLINE int run_pipe(struct pipe *pi)
G.ifs_whitespace = (char*)G.ifs;
}
+#ifndef __U_BOOT__
IF_HUSH_JOB(pi->pgrp = -1;)
pi->stopped_cmds = 0;
+#endif /* !__U_BOOT__ */
command = &pi->cmds[0];
argv_expanded = NULL;
+#ifndef __U_BOOT__
if (pi->num_cmds != 1
|| pi->followup == PIPE_BG
|| command->cmd_type == CMD_SUBSHELL
@@ -9243,6 +9669,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
}
pi->alive_cmds = 1;
+#endif /* !__U_BOOT__ */
debug_printf_exec(": group:%p argv:'%s'\n",
command->group, command->argv ? command->argv[0] : "NONE");
@@ -9274,6 +9701,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
/* { list } */
debug_printf_exec("non-subshell group\n");
rcode = 1; /* exitcode if redir failed */
+#ifndef __U_BOOT__
if (setup_redirects(command, &squirrel) == 0) {
debug_printf_exec(": run_list\n");
//FIXME: we need to pass squirrel down into run_list()
@@ -9286,6 +9714,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
}
restore_redirects(squirrel);
IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
+#endif /* !__U_BOOT__ */
debug_leave();
debug_printf_exec("run_pipe: return %d\n", rcode);
return rcode;
@@ -9293,10 +9722,12 @@ static NOINLINE int run_pipe(struct pipe *pi)
argv = command->argv ? command->argv : (char **) &null_ptr;
{
+#ifndef __U_BOOT__
const struct built_in_command *x;
IF_HUSH_FUNCTIONS(const struct function *funcp;)
IF_NOT_HUSH_FUNCTIONS(enum { funcp = 0 };)
struct variable **sv_shadowed;
+#endif /* !__U_BOOT__ */
struct variable *old_vars;
#if ENABLE_HUSH_LINENO_VAR
@@ -9311,8 +9742,10 @@ static NOINLINE int run_pipe(struct pipe *pi)
unsigned i;
G.expand_exitcode = 0;
only_assignments:
+#ifndef __U_BOOT__
rcode = setup_redirects(command, &squirrel);
restore_redirects(squirrel);
+#endif /* !__U_BOOT__ */
/* Set shell variables */
i = 0;
@@ -9335,7 +9768,11 @@ static NOINLINE int run_pipe(struct pipe *pi)
}
#endif
debug_printf_env("set shell var:'%s'->'%s'\n", *argv, p);
+#ifndef __U_BOOT__
if (set_local_var(p, /*flag:*/ 0)) {
+#else /* __U_BOOT__ */
+ if (set_local_var_2021(p, /*flag:*/ 0)) {
+#endif
/* assignment to readonly var / putenv error? */
rcode = 1;
}
@@ -9378,6 +9815,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
}
old_vars = NULL;
+#ifndef __U_BOOT__
sv_shadowed = G.shadowed_vars_pp;
/* Check if argv[0] matches any functions (this goes before bltins) */
@@ -9501,8 +9939,10 @@ static NOINLINE int run_pipe(struct pipe *pi)
debug_leave();
debug_printf_exec("run_pipe return %d\n", rcode);
return rcode;
+#endif /* !__U_BOOT__ */
}
+#ifndef __U_BOOT__
must_fork:
/* NB: argv_expanded may already be created, and that
* might include `cmd` runs! Do not rerun it! We *must*
@@ -9511,9 +9951,11 @@ static NOINLINE int run_pipe(struct pipe *pi)
/* Going to fork a child per each pipe member */
pi->alive_cmds = 0;
next_infd = 0;
+#endif /* !__U_BOOT__ */
cmd_no = 0;
while (cmd_no < pi->num_cmds) {
+#ifndef __U_BOOT__
struct fd_pair pipefds;
#if !BB_MMU
int sv_var_nest_level = G.var_nest_level;
@@ -9522,6 +9964,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
nommu_save.argv = NULL;
nommu_save.argv_from_re_execing = NULL;
#endif
+#endif /* !__U_BOOT__ */
command = &pi->cmds[cmd_no];
cmd_no++;
if (command->argv) {
@@ -9531,6 +9974,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
debug_printf_exec(": pipe member with no argv\n");
}
+#ifndef __U_BOOT__
/* pipes are inserted between pairs of commands */
pipefds.rd = 0;
pipefds.wr = 1;
@@ -9633,17 +10077,30 @@ static NOINLINE int run_pipe(struct pipe *pi)
close(pipefds.wr);
/* Pass read (output) pipe end to next iteration */
next_infd = pipefds.rd;
+#else /* __U_BOOT__ */
+ /* Process the command */
+ rcode = cmd_process(G.do_repeat ? CMD_FLAG_REPEAT : 0,
+ command->argc, command->argv,
+ &(G.flag_repeat), NULL);
+#endif /* __U_BOOT__ */
}
+#ifndef __U_BOOT__
if (!pi->alive_cmds) {
debug_leave();
debug_printf_exec("run_pipe return 1 (all forks failed, no children)\n");
return 1;
}
+#endif /* __U_BOOT__ */
debug_leave();
+#ifndef __U_BOOT__
debug_printf_exec("run_pipe return -1 (%u children started)\n", pi->alive_cmds);
return -1;
+#else /* __U_BOOT__ */
+ debug_printf_exec("run_pipe return %d\n", rcode);
+ return rcode;
+#endif /* __U_BOOT__ */
}
/* NB: called by pseudo_exec, and therefore must not modify any
@@ -9670,8 +10127,10 @@ static int run_list(struct pipe *pi)
smallint last_rword; /* ditto */
#endif
+#ifndef __U_BOOT__
debug_printf_exec("run_list start lvl %d\n", G.run_list_level);
debug_enter();
+#endif /* !__U_BOOT__ */
#if ENABLE_HUSH_LOOPS
/* Check syntax for "for" */
@@ -9719,10 +10178,15 @@ static int run_list(struct pipe *pi)
rcode = G.last_exitcode;
/* Go through list of pipes, (maybe) executing them. */
+#ifndef __U_BOOT__
for (; pi; pi = IF_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) {
+#else /* __U_BOOT__ */
+ for (; pi; pi = pi->next) {
+#endif /* __U_BOOT__ */
int r;
int sv_errexit_depth;
+#ifndef __U_BOOT__
if (G.flag_SIGINT)
break;
if (G_flag_return_in_progress == 1)
@@ -9732,6 +10196,7 @@ static int run_list(struct pipe *pi)
debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n",
rword, cond_code, last_rword);
+#endif /* !__U_BOOT__ */
sv_errexit_depth = G.errexit_depth;
if (
#if ENABLE_HUSH_IF
@@ -9885,8 +10350,10 @@ static int run_list(struct pipe *pi)
* OTOH, in non-interactive shell this is useless
* and only leads to extra job checks */
if (pi->num_cmds == 0) {
+#ifndef __U_BOOT__
if (G_interactive_fd)
goto check_jobs_and_continue;
+#endif /* !__U_BOOT__ */
continue;
}
@@ -9895,20 +10362,33 @@ static int run_list(struct pipe *pi)
* after run_pipe to collect any background children,
* even if list execution is to be stopped. */
debug_printf_exec(": run_pipe with %d members\n", pi->num_cmds);
+#ifndef __U_BOOT__
#if ENABLE_HUSH_LOOPS
G.flag_break_continue = 0;
#endif
+#endif /* !__U_BOOT__ */
rcode = r = run_pipe(pi); /* NB: rcode is a smalluint, r is int */
+#ifdef __U_BOOT__
+ if (r == -2) {
+ /* -2 indicates exit was called, so we need to quit now. */
+ G.last_exitcode = rcode;
+
+ break;
+ }
+#endif
if (r != -1) {
/* We ran a builtin, function, or group.
* rcode is already known
* and we don't need to wait for anything. */
debug_printf_exec(": builtin/func exitcode %d\n", rcode);
G.last_exitcode = rcode;
+#ifndef __U_BOOT__
check_and_run_traps();
+#endif /* !__U_BOOT__ */
#if ENABLE_HUSH_TRAP && ENABLE_HUSH_FUNCTIONS
rcode = G.last_exitcode; /* "return" in trap can change it, read back */
#endif
+#ifndef __U_BOOT__
#if ENABLE_HUSH_LOOPS
/* Was it "break" or "continue"? */
if (G.flag_break_continue) {
@@ -9934,6 +10414,7 @@ static int run_list(struct pipe *pi)
checkjobs(NULL, 0 /*(no pid to wait for)*/);
break;
}
+
} else if (pi->followup == PIPE_BG) {
/* What does bash do with attempts to background builtins? */
/* even bash 3.2 doesn't do that well with nested bg:
@@ -9969,13 +10450,18 @@ static int run_list(struct pipe *pi)
rcode = G.last_exitcode; /* "return" in trap can change it, read back */
#endif
}
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
/* Handle "set -e" */
if (rcode != 0 && G.o_opt[OPT_O_ERREXIT]) {
debug_printf_exec("ERREXIT:1 errexit_depth:%d\n", G.errexit_depth);
if (G.errexit_depth == 0)
hush_exit(rcode);
}
+#else /* __U_BOOT__ */
+ } /* if (r != -1) */
+#endif /* __U_BOOT__ */
G.errexit_depth = sv_errexit_depth;
/* Analyze how result affects subsequent commands */
@@ -9983,8 +10469,10 @@ static int run_list(struct pipe *pi)
if (rword == RES_IF || rword == RES_ELIF)
cond_code = rcode;
#endif
+#ifndef __U_BOOT__
check_jobs_and_continue:
checkjobs(NULL, 0 /*(no pid to wait for)*/);
+#endif /* !__U_BOOT__ */
dont_check_jobs_but_continue: ;
#if ENABLE_HUSH_LOOPS
/* Beware of "while false; true; do ..."! */
@@ -10021,8 +10509,10 @@ static int run_list(struct pipe *pi)
#if ENABLE_HUSH_CASE
free(case_word);
#endif
+#ifndef __U_BOOT__
debug_leave();
debug_printf_exec("run_list lvl %d return %d\n", G.run_list_level + 1, rcode);
+#endif /* !__U_BOOT__ */
return rcode;
}
@@ -10031,10 +10521,14 @@ static int run_and_free_list(struct pipe *pi)
{
int rcode = 0;
debug_printf_exec("run_and_free_list entered\n");
+#ifndef __U_BOOT__
if (!G.o_opt[OPT_O_NOEXEC]) {
+#endif /* !__U_BOOT__ */
debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds);
rcode = run_list(pi);
+#ifndef __U_BOOT__
}
+#endif /* !__U_BOOT__ */
/* free_pipe_list has the side effect of clearing memory.
* In the long run that function can be merged with run_list,
* but doing that now would hobble the debugging effort. */
@@ -10044,6 +10538,7 @@ static int run_and_free_list(struct pipe *pi)
}
+#ifndef __U_BOOT__
static void install_sighandlers(unsigned mask)
{
sighandler_t old_handler;
@@ -10460,6 +10955,7 @@ int hush_main(int argc, char **argv)
}
}
+#ifndef __U_BOOT__
/* -c takes effect *after* -l */
if (G.opt_c) {
/* Possibilities:
@@ -10536,6 +11032,7 @@ int hush_main(int argc, char **argv)
/* "implicit" -s: bare interactive hush shows 's' in $- */
G.opt_s = 1;
+#endif /* __U_BOOT__ */
/* Up to here, shell was non-interactive. Now it may become one.
* NB: don't forget to (re)run install_special_sighandlers() as needed.
*/
@@ -10681,6 +11178,7 @@ int hush_main(int argc, char **argv)
}
+
/*
* Built-ins
*/
@@ -12160,3 +12658,4 @@ static int FAST_FUNC builtin_memleak(char **argv UNUSED_PARAM)
return l;
}
#endif
+#endif /* !__U_BOOT__ */