//usage:#define hush_full_usage "\n\n"
//usage: "Unix shell interpreter"
+#ifndef __U_BOOT__
#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| defined(__APPLE__) \
)
#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 */
# 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 */
-# undef CONFIG_FEATURE_SH_STANDALONE
# undef ENABLE_FEATURE_SH_STANDALONE
# undef IF_FEATURE_SH_STANDALONE
# undef IF_NOT_FEATURE_SH_STANDALONE
# 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
#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 */
} nommu_save_t;
#endif
+
enum {
RES_NONE = 0,
#if ENABLE_HUSH_IF
HFILE *file;
} in_str;
+#ifndef __U_BOOT__
/* The descrip member of this structure is only used to make
* debugging output pretty */
static const struct {
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;
* 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)
* 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
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" */
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;
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 {
/* "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,
#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
#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
#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
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;
#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;
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 */
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
#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
#endif
};
+#endif /* !__U_BOOT__ */
/* Debug printouts.
*/
}
}
+#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;
die_if_script();
}
+#ifndef __U_BOOT__
static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg)
{
if (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)
{
# 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++;
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)
{
free(strings);
}
+#ifndef __U_BOOT__
static int dup_CLOEXEC(int fd, int avoid_fd)
{
int newfd;
return 0;
}
+#endif /* !__U_BOOT__ */
/* Helpers for setting new $n and restoring them back
*/
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];
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
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;
# 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;
}
return handler;
}
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
/* Restores tty foreground process group, and exits. */
static void hush_exit(int exitcode)
{
return G.cwd;
}
+#endif /* !__U_BOOT__ */
/*
* Shell and environment variable support
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)
return NULL;
}
+#ifndef __U_BOOT__
#if ENABLE_HUSH_GETOPTS
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_modern(char *str, int flags)
+#endif /* __U_BOOT__ */
{
struct variable **cur_pp;
struct variable *cur;
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)
continue;
}
+#ifndef __U_BOOT__
/* We found an existing var with this name */
if (cur->flg_read_only) {
bb_error_msg("%s: readonly variable", str);
}
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);
}
/* 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;
#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;
*/
}
}
+#endif /* !__U_BOOT__ */
free(free_me);
handle_changed_special_names(cur->varstr, name_len - 1);
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);
{
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)
#endif
+#ifndef __U_BOOT__
/*
* Helpers for "var1=val1 var2=val2 cmd" feature
*/
}
}
+#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\
* \
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.
}
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;
return EOF;
}
+#endif /* !__U_BOOT__ */
/* FILE-based in_str */
#if ENABLE_FEATURE_EDITING
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) {
goto out;
}
+#endif /* !__U_BOOT__ */
ch = fgetc_interactive(i);
out:
debug_printf("file_get: got '%c' %d\n", ch, ch);
static int i_peek(struct in_str *i)
{
+#ifndef __U_BOOT__
int ch;
if (!i->file) {
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.
*/
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.
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. */
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)
}
}
+#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));
i->p = s;
}
+#endif /* !__U_BOOT__ */
/*
* o_string support
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)
# define nommu_addchr(o, str) ((void)0)
#endif
+#ifndef __U_BOOT__
#if ENABLE_HUSH_MODE_X
static void x_mode_addchr(int ch)
{
G.x_mode_buf.length = 0;
}
#endif
+#endif /* !__U_BOOT__ */
/*
* HUSH_BRACE_EXPANSION code needs corresponding quoting on variable expansion side.
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
return ((int)(uintptr_t)list[n-1]) + string_start;
}
+#ifndef __U_BOOT__
/*
* Globbing routines.
*
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)
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);
}
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);
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);
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);
[PIPE_OR ] = "OR" ,
[PIPE_BG ] = "BG" ,
};
+#ifndef __U_BOOT__
static const char *RES[] = {
[RES_NONE ] = "NONE" ,
# if ENABLE_HUSH_IF
[RES_XXXX ] = "XXXX" ,
[RES_SNTX ] = "SNTX" ,
};
+#endif /* !__U_BOOT__ */
static const char *const CMDTYPE[] = {
"{}",
"()",
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;
fdprintf(2, " '%s'", *argv);
argv++;
}
+#ifndef __U_BOOT__
if (command->redirects)
fdprintf(2, " {redir}");
+#endif /* __U_BOOT__ */
fdprintf(2, "\n");
prn++;
}
) {
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;
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" */
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
}
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) {
}
+#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:
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';
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.
*/
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.
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;
}
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);
}
#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);
#undef as_string
}
+#ifndef __U_BOOT__
#if ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS
/* Subroutines for copying $(...) and `...` things */
/* '...' */
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)
//if (ch == '$') ...
}
}
+
+
/* Process `cmd` - copy contents until "`" is seen. Complicated by
* \` quoting.
* "Within the backquoted style of command substitution, backslash
#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
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 */
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
*/
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))
}
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,
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)
) {
o_addstr(dest, "999999999");
} /* else: it's ${var/[/]pattern} */
}
+#endif /* !__U_BOOT__ */
break;
}
len_single_ch = 0; /* it can't be ${#C} op */
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",
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) {
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) {
* } 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 /* ""} */
) {
/* 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)) {
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" */
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 */
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");
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);
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`"
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)
{
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)
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)
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 == ':') {
}
*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;
*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();
*exp_saveptr = exp_save;
} /* if (exp_op) */
+#endif /* !__U_BOOT__ */
arg[0] = arg0;
*pp = p;
}
#endif
+#ifndef __U_BOOT__
static char **expand_assignments(char **argv, int count)
{
int i;
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,
}
#endif /* !BB_MMU */
+#endif /* !__U_BOOT__ */
static int run_and_free_list(struct pipe *pi);
}
}
+#ifndef __U_BOOT__
static void parse_and_run_string(const char *s)
{
struct in_str input;
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)
{
return NULL;
}
#endif
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
static void remove_nested_vars(void)
{
struct variable *cur;
remove_nested_vars();
}
+#endif /* __U_BOOT__ */
#if ENABLE_HUSH_FUNCTIONS
static struct function **find_function_slot(const char *name)
#endif /* ENABLE_HUSH_FUNCTIONS */
+#ifndef __U_BOOT__
#if BB_MMU
#define exec_builtin(to_free, x, argv) \
exec_builtin(x, argv)
argv);
#endif
}
+#endif /* !__U_BOOT__ */
+#ifndef __U_BOOT__
static void execvp_or_die(char **argv) NORETURN;
static void execvp_or_die(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)
{
#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) \
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.
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();
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
}
pi->alive_cmds = 1;
+#endif /* !__U_BOOT__ */
debug_printf_exec(": group:%p argv:'%s'\n",
command->group, command->argv ? command->argv[0] : "NONE");
/* { 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()
}
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;
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
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;
}
#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_modern(p, /*flag:*/ 0)) {
+#endif
/* assignment to readonly var / putenv error? */
rcode = 1;
}
}
old_vars = NULL;
+#ifndef __U_BOOT__
sv_shadowed = G.shadowed_vars_pp;
/* Check if argv[0] matches any functions (this goes before bltins) */
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*
/* 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;
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) {
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;
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
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" */
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)
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
* 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;
}
* 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) {
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:
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 */
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 ..."! */
#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;
}
{
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. */
}
+#ifndef __U_BOOT__
static void install_sighandlers(unsigned mask)
{
sighandler_t old_handler;
}
}
+#ifndef __U_BOOT__
/* -c takes effect *after* -l */
if (G.opt_c) {
/* Possibilities:
/* "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.
*/
}
+
/*
* Built-ins
*/
return l;
}
#endif
+#endif /* !__U_BOOT__ */