aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--shell/hush.c468
1 files changed, 249 insertions, 219 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 0b2bc01f5..09ab6ebc0 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -392,6 +392,8 @@
392 392
393/* Build knobs */ 393/* Build knobs */
394#define LEAK_HUNTING 0 394#define LEAK_HUNTING 0
395#define LEAK_PRINTF(...) fdprintf(__VA_ARGS__)
396//#define LEAK_PRINTF(...) do { if (ptr_to_globals && G.root_pid == getpid()) fdprintf(__VA_ARGS__); } while (0)
395#define BUILD_AS_NOMMU 0 397#define BUILD_AS_NOMMU 0
396/* Enable/disable sanity checks. Ok to enable in production, 398/* Enable/disable sanity checks. Ok to enable in production,
397 * only adds a bit of bloat. Set to >1 to get non-production level verbosity. 399 * only adds a bit of bloat. Set to >1 to get non-production level verbosity.
@@ -930,6 +932,12 @@ struct globals {
930# define G_flag_return_in_progress 0 932# define G_flag_return_in_progress 0
931#endif 933#endif
932 smallint exiting; /* used to prevent EXIT trap recursion */ 934 smallint exiting; /* used to prevent EXIT trap recursion */
935#if !BB_MMU
936 smallint reexeced_on_NOMMU;
937# define G_reexeced_on_NOMMU (G.reexeced_on_NOMMU)
938#else
939# define G_reexeced_on_NOMMU 0
940#endif
933 /* These support $? */ 941 /* These support $? */
934 smalluint last_exitcode; 942 smalluint last_exitcode;
935 smalluint expand_exitcode; 943 smalluint expand_exitcode;
@@ -1352,30 +1360,67 @@ static void debug_print_strings(const char *prefix, char **vv)
1352static void *xxmalloc(int lineno, size_t size) 1360static void *xxmalloc(int lineno, size_t size)
1353{ 1361{
1354 void *ptr = xmalloc((size + 0xff) & ~0xff); 1362 void *ptr = xmalloc((size + 0xff) & ~0xff);
1355 fdprintf(2, "line %d: malloc %p\n", lineno, ptr); 1363 LEAK_PRINTF(2, "line %d: malloc %p\n", lineno, ptr);
1364 return ptr;
1365}
1366static void *xxzalloc(int lineno, size_t size)
1367{
1368 void *ptr = xzalloc((size + 0xff) & ~0xff);
1369 LEAK_PRINTF(2, "line %d: zalloc %p\n", lineno, ptr);
1356 return ptr; 1370 return ptr;
1357} 1371}
1358static void *xxrealloc(int lineno, void *ptr, size_t size) 1372static void *xxrealloc(int lineno, void *ptr, size_t size)
1359{ 1373{
1374 char *p = ptr;
1360 ptr = xrealloc(ptr, (size + 0xff) & ~0xff); 1375 ptr = xrealloc(ptr, (size + 0xff) & ~0xff);
1361 fdprintf(2, "line %d: realloc %p\n", lineno, ptr); 1376 if (p != ptr)
1377 LEAK_PRINTF(2, "line %d: realloc %p\n", lineno, ptr);
1378 return ptr;
1379}
1380static void *xxrealloc_getcwd_or_warn(int lineno, char *ptr)
1381{
1382 char *p = ptr;
1383 ptr = xrealloc_getcwd_or_warn(ptr);
1384 if (p != ptr)
1385 LEAK_PRINTF(2, "line %d: xrealloc_getcwd_or_warn %p\n", lineno, ptr);
1362 return ptr; 1386 return ptr;
1363} 1387}
1364static char *xxstrdup(int lineno, const char *str) 1388static char *xxstrdup(int lineno, const char *str)
1365{ 1389{
1366 char *ptr = xstrdup(str); 1390 char *ptr = xstrdup(str);
1367 fdprintf(2, "line %d: strdup %p\n", lineno, ptr); 1391 LEAK_PRINTF(2, "line %d: strdup %p\n", lineno, ptr);
1392 return ptr;
1393}
1394static char *xxstrndup(int lineno, const char *str, size_t n)
1395{
1396 char *ptr = xstrndup(str, n);
1397 LEAK_PRINTF(2, "line %d: strndup %p\n", lineno, ptr);
1398 return ptr;
1399}
1400static char *xxasprintf(int lineno, const char *f, ...)
1401{
1402 char *ptr;
1403 va_list args;
1404 va_start(args, f);
1405 if (vasprintf(&ptr, f, args) < 0)
1406 bb_die_memory_exhausted();
1407 va_end(args);
1408 LEAK_PRINTF(2, "line %d: xasprintf %p\n", lineno, ptr);
1368 return ptr; 1409 return ptr;
1369} 1410}
1370static void xxfree(void *ptr) 1411static void xxfree(void *ptr)
1371{ 1412{
1372 fdprintf(2, "free %p\n", ptr); 1413 LEAK_PRINTF(2, "free %p\n", ptr);
1373 free(ptr); 1414 free(ptr);
1374} 1415}
1375# define xmalloc(s) xxmalloc(__LINE__, s) 1416# define xmalloc(s) xxmalloc(__LINE__, s)
1376# define xrealloc(p, s) xxrealloc(__LINE__, p, s) 1417# define xzalloc(s) xxzalloc(__LINE__, s)
1377# define xstrdup(s) xxstrdup(__LINE__, s) 1418# define xrealloc(p, s) xxrealloc(__LINE__, p, s)
1378# define free(p) xxfree(p) 1419# define xrealloc_getcwd_or_warn(p) xxrealloc_getcwd_or_warn(__LINE__, p)
1420# define xstrdup(s) xxstrdup(__LINE__, s)
1421# define xstrndup(s, n) xxstrndup(__LINE__, s, n)
1422# define xasprintf(f, ...) xxasprintf(__LINE__, f, __VA_ARGS__)
1423# define free(p) xxfree(p)
1379#endif 1424#endif
1380 1425
1381/* 1426/*
@@ -1929,7 +1974,7 @@ static void restore_G_args(save_arg_t *sv, char **argv)
1929 * "trap - SIGxxx": 1974 * "trap - SIGxxx":
1930 * if sig is in special_sig_mask, set handler back to: 1975 * if sig is in special_sig_mask, set handler back to:
1931 * record_pending_signo, or to IGN if it's a tty stop signal 1976 * record_pending_signo, or to IGN if it's a tty stop signal
1932 * if sig is in fatal_sig_mask, set handler back to sigexit. 1977 * if sig is in fatal_sig_mask, set handler back to restore_ttypgrp_and_killsig_or__exit.
1933 * else: set handler back to SIG_DFL 1978 * else: set handler back to SIG_DFL
1934 * "trap 'cmd' SIGxxx": 1979 * "trap 'cmd' SIGxxx":
1935 * set handler to record_pending_signo. 1980 * set handler to record_pending_signo.
@@ -2002,19 +2047,6 @@ static sighandler_t install_sighandler(int sig, sighandler_t handler)
2002 return old_sa.sa_handler; 2047 return old_sa.sa_handler;
2003} 2048}
2004 2049
2005static void hush_exit(int exitcode) NORETURN;
2006
2007static void restore_ttypgrp_and__exit(void) NORETURN;
2008static void restore_ttypgrp_and__exit(void)
2009{
2010 /* xfunc has failed! die die die */
2011 /* no EXIT traps, this is an escape hatch! */
2012 G.exiting = 1;
2013 hush_exit(xfunc_error_retval);
2014}
2015
2016#if ENABLE_HUSH_JOB
2017
2018/* Needed only on some libc: 2050/* Needed only on some libc:
2019 * It was observed that on exit(), fgetc'ed buffered data 2051 * It was observed that on exit(), fgetc'ed buffered data
2020 * gets "unwound" via lseek(fd, -NUM, SEEK_CUR). 2052 * gets "unwound" via lseek(fd, -NUM, SEEK_CUR).
@@ -2028,26 +2060,20 @@ static void restore_ttypgrp_and__exit(void)
2028 * and in `cmd` handling. 2060 * and in `cmd` handling.
2029 * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit(): 2061 * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit():
2030 */ 2062 */
2031static void fflush_and__exit(void) NORETURN; 2063static NORETURN void fflush_and__exit(void)
2032static void fflush_and__exit(void)
2033{ 2064{
2034 fflush_all(); 2065 fflush_all();
2035 _exit(xfunc_error_retval); 2066 _exit(xfunc_error_retval);
2036} 2067}
2037 2068
2038/* After [v]fork, in child: do not restore tty pgrp on xfunc death */ 2069#if ENABLE_HUSH_JOB
2039# define disable_restore_tty_pgrp_on_exit() (die_func = fflush_and__exit)
2040/* After [v]fork, in parent: restore tty pgrp on xfunc death */
2041# define enable_restore_tty_pgrp_on_exit() (die_func = restore_ttypgrp_and__exit)
2042
2043/* Restores tty foreground process group, and exits. 2070/* Restores tty foreground process group, and exits.
2044 * May be called as signal handler for fatal signal 2071 * May be called as signal handler for fatal signal
2045 * (will resend signal to itself, producing correct exit state) 2072 * (will resend signal to itself, producing correct exit state)
2046 * or called directly with -EXITCODE. 2073 * or called directly with -EXITCODE.
2047 * We also call it if xfunc is exiting. 2074 * We also call it if xfunc is exiting.
2048 */ 2075 */
2049static void sigexit(int sig) NORETURN; 2076static NORETURN void restore_ttypgrp_and_killsig_or__exit(int sig)
2050static void sigexit(int sig)
2051{ 2077{
2052 /* Careful: we can end up here after [v]fork. Do not restore 2078 /* Careful: we can end up here after [v]fork. Do not restore
2053 * tty pgrp then, only top-level shell process does that */ 2079 * tty pgrp then, only top-level shell process does that */
@@ -2065,6 +2091,19 @@ static void sigexit(int sig)
2065 2091
2066 kill_myself_with_sig(sig); /* does not return */ 2092 kill_myself_with_sig(sig); /* does not return */
2067} 2093}
2094
2095static NORETURN void fflush_restore_ttypgrp_and__exit(void)
2096{
2097 /* xfunc has failed! die die die */
2098 fflush_all();
2099 restore_ttypgrp_and_killsig_or__exit(- xfunc_error_retval);
2100}
2101
2102/* After [v]fork, in child: do not restore tty pgrp on xfunc death */
2103# define disable_restore_tty_pgrp_on_exit() (die_func = fflush_and__exit)
2104/* After [v]fork, in parent: restore tty pgrp on xfunc death */
2105# define enable_restore_tty_pgrp_on_exit() (die_func = fflush_restore_ttypgrp_and__exit)
2106
2068#else 2107#else
2069 2108
2070# define disable_restore_tty_pgrp_on_exit() ((void)0) 2109# define disable_restore_tty_pgrp_on_exit() ((void)0)
@@ -2081,7 +2120,7 @@ static sighandler_t pick_sighandler(unsigned sig)
2081#if ENABLE_HUSH_JOB 2120#if ENABLE_HUSH_JOB
2082 /* is sig fatal? */ 2121 /* is sig fatal? */
2083 if (G_fatal_sig_mask & sigmask) 2122 if (G_fatal_sig_mask & sigmask)
2084 handler = sigexit; 2123 handler = restore_ttypgrp_and_killsig_or__exit;
2085 else 2124 else
2086#endif 2125#endif
2087 /* sig has special handling? */ 2126 /* sig has special handling? */
@@ -2101,11 +2140,15 @@ static sighandler_t pick_sighandler(unsigned sig)
2101 2140
2102static const char* FAST_FUNC get_local_var_value(const char *name); 2141static const char* FAST_FUNC get_local_var_value(const char *name);
2103 2142
2104/* Restores tty foreground process group, and exits. */ 2143/* Self-explanatory.
2105static void hush_exit(int exitcode) 2144 * Restores tty foreground process group too.
2145 */
2146static NORETURN void save_history_run_exit_trap_and_exit(int exitcode)
2106{ 2147{
2107#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 2148#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
2108 if (G.line_input_state) { 2149 if (G.line_input_state
2150 && getpid() == G.root_pid /* exits in subshells do not save history */
2151 ) {
2109 const char *hp; 2152 const char *hp;
2110# if ENABLE_FEATURE_SH_HISTFILESIZE 2153# if ENABLE_FEATURE_SH_HISTFILESIZE
2111// in bash: 2154// in bash:
@@ -2155,7 +2198,7 @@ static void hush_exit(int exitcode)
2155 2198
2156 fflush_all(); 2199 fflush_all();
2157#if ENABLE_HUSH_JOB 2200#if ENABLE_HUSH_JOB
2158 sigexit(- (exitcode & 0xff)); 2201 restore_ttypgrp_and_killsig_or__exit(- (exitcode & 0xff));
2159#else 2202#else
2160 _exit(exitcode); 2203 _exit(exitcode);
2161#endif 2204#endif
@@ -2240,7 +2283,7 @@ static int check_and_run_traps(void)
2240 } 2283 }
2241 } 2284 }
2242 /* this restores tty pgrp, then kills us with SIGHUP */ 2285 /* this restores tty pgrp, then kills us with SIGHUP */
2243 sigexit(SIGHUP); 2286 restore_ttypgrp_and_killsig_or__exit(SIGHUP);
2244 } 2287 }
2245#endif 2288#endif
2246#if ENABLE_HUSH_FAST 2289#if ENABLE_HUSH_FAST
@@ -4625,6 +4668,11 @@ static int fetch_heredocs(o_string *as_string, struct pipe *pi, int heredoc_cnt,
4625 4668
4626 redir->rd_type = REDIRECT_HEREDOC2; 4669 redir->rd_type = REDIRECT_HEREDOC2;
4627 /* redir->rd_dup is (ab)used to indicate <<- */ 4670 /* redir->rd_dup is (ab)used to indicate <<- */
4671 if (!redir->rd_filename) {
4672 /* examples: "echo <<", "echo <<<", "echo <<>" */
4673 syntax_error("missing here document terminator");
4674 return -1;
4675 }
4628 p = fetch_till_str(as_string, input, 4676 p = fetch_till_str(as_string, input,
4629 redir->rd_filename, redir->rd_dup); 4677 redir->rd_filename, redir->rd_dup);
4630 if (!p) { 4678 if (!p) {
@@ -7384,11 +7432,6 @@ static void switch_off_special_sigs(unsigned mask)
7384} 7432}
7385 7433
7386#if BB_MMU 7434#if BB_MMU
7387/* never called */
7388void re_execute_shell(char ***to_free, const char *s,
7389 char *g_argv0, char **g_argv,
7390 char **builtin_argv) NORETURN;
7391
7392static void reset_traps_to_defaults(void) 7435static void reset_traps_to_defaults(void)
7393{ 7436{
7394 /* This function is always called in a child shell 7437 /* This function is always called in a child shell
@@ -7438,10 +7481,8 @@ static void reset_traps_to_defaults(void)
7438 7481
7439#else /* !BB_MMU */ 7482#else /* !BB_MMU */
7440 7483
7441static void re_execute_shell(char ***to_free, const char *s, 7484static NORETURN void re_execute_shell(
7442 char *g_argv0, char **g_argv, 7485 char * *volatile * to_free, const char *s,
7443 char **builtin_argv) NORETURN;
7444static void re_execute_shell(char ***to_free, const char *s,
7445 char *g_argv0, char **g_argv, 7486 char *g_argv0, char **g_argv,
7446 char **builtin_argv) 7487 char **builtin_argv)
7447{ 7488{
@@ -7671,7 +7712,13 @@ static int generate_stream_from_string(const char *s, pid_t *pid_p)
7671 pid_t pid; 7712 pid_t pid;
7672 int channel[2]; 7713 int channel[2];
7673# if !BB_MMU 7714# if !BB_MMU
7674 char **to_free = NULL; 7715 /* _volatile_ pointer to "char*".
7716 * Or else compiler can peek from inside re_execute_shell()
7717 * and see that this pointer is a local var (i.e. not globally visible),
7718 * and decide to optimize out the store to it. Yes,
7719 * it was seen in the wild.
7720 */
7721 char * *volatile to_free = NULL;
7675# endif 7722# endif
7676 7723
7677 xpipe(channel); 7724 xpipe(channel);
@@ -7818,7 +7865,7 @@ static void setup_heredoc(struct redir_struct *redir)
7818 const char *heredoc = redir->rd_filename; 7865 const char *heredoc = redir->rd_filename;
7819 char *expanded; 7866 char *expanded;
7820#if !BB_MMU 7867#if !BB_MMU
7821 char **to_free; 7868 char * *volatile to_free;
7822#endif 7869#endif
7823 7870
7824 expanded = NULL; 7871 expanded = NULL;
@@ -8293,7 +8340,7 @@ static const struct built_in_command *find_builtin(const char *name)
8293 return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]); 8340 return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]);
8294} 8341}
8295 8342
8296#if ENABLE_HUSH_JOB && ENABLE_FEATURE_TAB_COMPLETION 8343#if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_TAB_COMPLETION
8297static const char * FAST_FUNC hush_command_name(int i) 8344static const char * FAST_FUNC hush_command_name(int i)
8298{ 8345{
8299 if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) { 8346 if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) {
@@ -8459,10 +8506,8 @@ static void unset_func(const char *name)
8459#define exec_function(to_free, funcp, argv) \ 8506#define exec_function(to_free, funcp, argv) \
8460 exec_function(funcp, argv) 8507 exec_function(funcp, argv)
8461# endif 8508# endif
8462static void exec_function(char ***to_free, 8509static NORETURN void exec_function(
8463 const struct function *funcp, 8510 char * *volatile *to_free,
8464 char **argv) NORETURN;
8465static void exec_function(char ***to_free,
8466 const struct function *funcp, 8511 const struct function *funcp,
8467 char **argv) 8512 char **argv)
8468{ 8513{
@@ -8558,10 +8603,8 @@ static int run_function(const struct function *funcp, char **argv)
8558#define exec_builtin(to_free, x, argv) \ 8603#define exec_builtin(to_free, x, argv) \
8559 exec_builtin(to_free, argv) 8604 exec_builtin(to_free, argv)
8560#endif 8605#endif
8561static void exec_builtin(char ***to_free, 8606static NORETURN void exec_builtin(
8562 const struct built_in_command *x, 8607 char * *volatile *to_free,
8563 char **argv) NORETURN;
8564static void exec_builtin(char ***to_free,
8565 const struct built_in_command *x, 8608 const struct built_in_command *x,
8566 char **argv) 8609 char **argv)
8567{ 8610{
@@ -8584,8 +8627,7 @@ static void exec_builtin(char ***to_free,
8584#endif 8627#endif
8585} 8628}
8586 8629
8587static void execvp_or_die(char **argv) NORETURN; 8630static NORETURN void execvp_or_die(char **argv)
8588static void execvp_or_die(char **argv)
8589{ 8631{
8590 int e; 8632 int e;
8591 debug_printf_exec("execing '%s'\n", argv[0]); 8633 debug_printf_exec("execing '%s'\n", argv[0]);
@@ -8706,10 +8748,8 @@ static void if_command_vV_print_and_exit(char opt_vV, char *cmd, const char *exp
8706 * The at_exit handlers apparently confuse the calling process, 8748 * The at_exit handlers apparently confuse the calling process,
8707 * in particular stdin handling. Not sure why? -- because of vfork! (vda) 8749 * in particular stdin handling. Not sure why? -- because of vfork! (vda)
8708 */ 8750 */
8709static void pseudo_exec_argv(nommu_save_t *nommu_save, 8751static NORETURN NOINLINE void pseudo_exec_argv(
8710 char **argv, int assignment_cnt, 8752 volatile nommu_save_t *nommu_save,
8711 char **argv_expanded) NORETURN;
8712static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
8713 char **argv, int assignment_cnt, 8753 char **argv, int assignment_cnt,
8714 char **argv_expanded) 8754 char **argv_expanded)
8715{ 8755{
@@ -8735,7 +8775,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
8735#if BB_MMU 8775#if BB_MMU
8736 G.shadowed_vars_pp = NULL; /* "don't save, free them instead" */ 8776 G.shadowed_vars_pp = NULL; /* "don't save, free them instead" */
8737#else 8777#else
8738 G.shadowed_vars_pp = &nommu_save->old_vars; 8778 /* cast away volatility */
8779 G.shadowed_vars_pp = (struct variable **)&nommu_save->old_vars;
8739 G.var_nest_level++; 8780 G.var_nest_level++;
8740#endif 8781#endif
8741 set_vars_and_save_old(new_env); 8782 set_vars_and_save_old(new_env);
@@ -8862,10 +8903,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save,
8862 8903
8863/* Called after [v]fork() in run_pipe 8904/* Called after [v]fork() in run_pipe
8864 */ 8905 */
8865static void pseudo_exec(nommu_save_t *nommu_save, 8906static NORETURN void pseudo_exec(
8866 struct command *command, 8907 volatile nommu_save_t *nommu_save,
8867 char **argv_expanded) NORETURN;
8868static void pseudo_exec(nommu_save_t *nommu_save,
8869 struct command *command, 8908 struct command *command,
8870 char **argv_expanded) 8909 char **argv_expanded)
8871{ 8910{
@@ -9750,8 +9789,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
9750 9789
9751 /* Stores to nommu_save list of env vars putenv'ed 9790 /* Stores to nommu_save list of env vars putenv'ed
9752 * (NOMMU, on MMU we don't need that) */ 9791 * (NOMMU, on MMU we don't need that) */
9753 /* cast away volatility... */ 9792 pseudo_exec(&nommu_save, command, argv_expanded);
9754 pseudo_exec((nommu_save_t*) &nommu_save, command, argv_expanded);
9755 /* pseudo_exec() does not return */ 9793 /* pseudo_exec() does not return */
9756 } 9794 }
9757 9795
@@ -10139,7 +10177,7 @@ static int run_list(struct pipe *pi)
10139 if (rcode != 0 && G.o_opt[OPT_O_ERREXIT]) { 10177 if (rcode != 0 && G.o_opt[OPT_O_ERREXIT]) {
10140 debug_printf_exec("ERREXIT:1 errexit_depth:%d\n", G.errexit_depth); 10178 debug_printf_exec("ERREXIT:1 errexit_depth:%d\n", G.errexit_depth);
10141 if (G.errexit_depth == 0) 10179 if (G.errexit_depth == 0)
10142 hush_exit(rcode); 10180 save_history_run_exit_trap_and_exit(rcode);
10143 } 10181 }
10144 G.errexit_depth = sv_errexit_depth; 10182 G.errexit_depth = sv_errexit_depth;
10145 10183
@@ -10213,6 +10251,53 @@ static int run_and_free_list(struct pipe *pi)
10213/* 10251/*
10214 * Initialization and main 10252 * Initialization and main
10215 */ 10253 */
10254#if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING
10255static void init_line_editing(void)
10256{
10257 G.line_input_state = new_line_input_t(FOR_SHELL);
10258# if ENABLE_FEATURE_TAB_COMPLETION
10259 G.line_input_state->get_exe_name = hush_command_name;
10260# endif
10261# if EDITING_HAS_sh_get_var
10262 G.line_input_state->sh_get_var = get_local_var_value;
10263# endif
10264# if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0
10265 {
10266 const char *hp = get_local_var_value("HISTFILE");
10267 if (!hp) {
10268 hp = get_local_var_value("HOME");
10269 if (hp) {
10270 hp = concat_path_file(hp, ".hush_history");
10271 /* Make HISTFILE set on exit (else history won't be saved) */
10272 set_local_var_from_halves("HISTFILE", hp);
10273 }
10274 } else {
10275 hp = xstrdup(hp);
10276 }
10277 if (hp) {
10278 G.line_input_state->hist_file = hp;
10279 }
10280# if ENABLE_FEATURE_SH_HISTFILESIZE
10281 hp = get_local_var_value("HISTSIZE");
10282 /* Using HISTFILESIZE above to limit max_history would be WRONG:
10283 * users may set HISTFILESIZE=0 in their profile scripts
10284 * to prevent _saving_ of history files, but still want to have
10285 * non-zero history limit for in-memory list.
10286 */
10287// in bash, runtime history size is controlled by HISTSIZE (0=no history),
10288// HISTFILESIZE controls on-disk history file size (in lines, 0=no history):
10289 G.line_input_state->max_history = size_from_HISTFILESIZE(hp);
10290// HISTFILESIZE: "The shell sets the default value to the value of HISTSIZE after reading any startup files."
10291// HISTSIZE: "The shell sets the default value to 500 after reading any startup files."
10292// (meaning: if the value wasn't set after startup files, the default value is set as described above)
10293# endif
10294 }
10295# endif
10296}
10297#else
10298# define init_line_editing() ((void)0)
10299#endif
10300
10216static void install_sighandlers(unsigned mask) 10301static void install_sighandlers(unsigned mask)
10217{ 10302{
10218 sighandler_t old_handler; 10303 sighandler_t old_handler;
@@ -10351,7 +10436,6 @@ static int set_mode(int state, char mode, const char *o_opt)
10351int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 10436int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
10352int hush_main(int argc, char **argv) 10437int hush_main(int argc, char **argv)
10353{ 10438{
10354 pid_t cached_getpid;
10355 enum { 10439 enum {
10356 OPT_login = (1 << 0), 10440 OPT_login = (1 << 0),
10357 }; 10441 };
@@ -10364,6 +10448,11 @@ int hush_main(int argc, char **argv)
10364 struct variable *shell_ver; 10448 struct variable *shell_ver;
10365 10449
10366 INIT_G(); 10450 INIT_G();
10451#if ENABLE_HUSH_JOB
10452 die_func = fflush_restore_ttypgrp_and__exit;
10453#else
10454 die_func = fflush_and__exit;
10455#endif
10367 if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ 10456 if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */
10368 G.last_exitcode = EXIT_SUCCESS; 10457 G.last_exitcode = EXIT_SUCCESS;
10369#if !BB_MMU 10458#if !BB_MMU
@@ -10379,9 +10468,6 @@ int hush_main(int argc, char **argv)
10379 _exit(0); 10468 _exit(0);
10380 } 10469 }
10381 G.argv0_for_re_execing = argv[0]; 10470 G.argv0_for_re_execing = argv[0];
10382 if (G.argv0_for_re_execing[0] == '-')
10383 /* reexeced hush should never be a login shell */
10384 G.argv0_for_re_execing++;
10385#endif 10471#endif
10386#if ENABLE_HUSH_TRAP 10472#if ENABLE_HUSH_TRAP
10387# if ENABLE_HUSH_FUNCTIONS 10473# if ENABLE_HUSH_FUNCTIONS
@@ -10394,9 +10480,8 @@ int hush_main(int argc, char **argv)
10394 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ 10480 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */
10395#endif 10481#endif
10396 10482
10397 cached_getpid = getpid(); /* for tcsetpgrp() during init */ 10483 G.root_pid = getpid(); /* for $PID (NOMMU can override via -$HEXPID:HEXPPID:...) */
10398 G.root_pid = cached_getpid; /* for $PID (NOMMU can override via -$HEXPID:HEXPPID:...) */ 10484 G.root_ppid = getppid(); /* for $PPID (NOMMU can override) */
10399 G.root_ppid = getppid(); /* for $PPID (NOMMU can override) */
10400 10485
10401 /* Deal with HUSH_VERSION */ 10486 /* Deal with HUSH_VERSION */
10402 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); 10487 debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION");
@@ -10479,27 +10564,24 @@ int hush_main(int argc, char **argv)
10479 * PS4='+ ' 10564 * PS4='+ '
10480 */ 10565 */
10481 10566
10567 /* Shell is non-interactive at first. We need to call
10568 * install_special_sighandlers() if we are going to execute "sh <script>",
10569 * "sh -c <cmds>" or login shell's /etc/profile and friends.
10570 * If we later decide that we are interactive, we run
10571 * install_special_sighandlers() in order to intercept more signals.
10572 */
10573 install_special_sighandlers();
10574
10482#if NUM_SCRIPTS > 0 10575#if NUM_SCRIPTS > 0
10483 if (argc < 0) { 10576 if (argc < 0) {
10484 char *script = get_script_content(-argc - 1); 10577 char *script = get_script_content(-argc - 1);
10485 G.global_argv = argv; 10578 G.global_argv = argv;
10486 G.global_argc = string_array_len(argv); 10579 G.global_argc = string_array_len(argv);
10487 //install_special_sighandlers(); - needed?
10488 parse_and_run_string(script); 10580 parse_and_run_string(script);
10489 goto final_return; 10581 goto final_return;
10490 } 10582 }
10491#endif 10583#endif
10492 10584
10493 /* Initialize some more globals to non-zero values */
10494 die_func = restore_ttypgrp_and__exit;
10495
10496 /* Shell is non-interactive at first. We need to call
10497 * install_special_sighandlers() if we are going to execute "sh <script>",
10498 * "sh -c <cmds>" or login shell's /etc/profile and friends.
10499 * If we later decide that we are interactive, we run install_special_sighandlers()
10500 * in order to intercept (more) signals.
10501 */
10502
10503 /* Parse options */ 10585 /* Parse options */
10504 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ 10586 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */
10505 flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; 10587 flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0;
@@ -10563,6 +10645,7 @@ int hush_main(int argc, char **argv)
10563 case '$': { 10645 case '$': {
10564 unsigned long long empty_trap_mask; 10646 unsigned long long empty_trap_mask;
10565 10647
10648 G.reexeced_on_NOMMU = 1;
10566 G.root_pid = bb_strtou(optarg, &optarg, 16); 10649 G.root_pid = bb_strtou(optarg, &optarg, 16);
10567 optarg++; 10650 optarg++;
10568 G.root_ppid = bb_strtou(optarg, &optarg, 16); 10651 G.root_ppid = bb_strtou(optarg, &optarg, 16);
@@ -10576,7 +10659,6 @@ int hush_main(int argc, char **argv)
10576 empty_trap_mask = bb_strtoull(optarg, &optarg, 16); 10659 empty_trap_mask = bb_strtoull(optarg, &optarg, 16);
10577 if (empty_trap_mask != 0) { 10660 if (empty_trap_mask != 0) {
10578 IF_HUSH_TRAP(int sig;) 10661 IF_HUSH_TRAP(int sig;)
10579 install_special_sighandlers();
10580# if ENABLE_HUSH_TRAP 10662# if ENABLE_HUSH_TRAP
10581 G_traps = xzalloc(sizeof(G_traps[0]) * NSIG); 10663 G_traps = xzalloc(sizeof(G_traps[0]) * NSIG);
10582 for (sig = 1; sig < NSIG; sig++) { 10664 for (sig = 1; sig < NSIG; sig++) {
@@ -10642,7 +10724,9 @@ int hush_main(int argc, char **argv)
10642 G.global_argv[0] = argv[0]; 10724 G.global_argv[0] = argv[0];
10643 10725
10644 /* If we are login shell... */ 10726 /* If we are login shell... */
10645 if (flags & OPT_login) { 10727 if (!G_reexeced_on_NOMMU /* reexeced hush should never be a login shell */
10728 && (flags & OPT_login)
10729 ) {
10646 const char *hp = NULL; 10730 const char *hp = NULL;
10647 HFILE *input; 10731 HFILE *input;
10648 10732
@@ -10650,7 +10734,6 @@ int hush_main(int argc, char **argv)
10650 input = hfopen("/etc/profile"); 10734 input = hfopen("/etc/profile");
10651 run_profile: 10735 run_profile:
10652 if (input != NULL) { 10736 if (input != NULL) {
10653 install_special_sighandlers();
10654 parse_and_run_file(input); 10737 parse_and_run_file(input);
10655 hfclose(input); 10738 hfclose(input);
10656 } 10739 }
@@ -10687,8 +10770,6 @@ int hush_main(int argc, char **argv)
10687 */ 10770 */
10688 char *script; 10771 char *script;
10689 10772
10690 install_special_sighandlers();
10691
10692 G.global_argc--; 10773 G.global_argc--;
10693 G.global_argv++; 10774 G.global_argv++;
10694#if !BB_MMU 10775#if !BB_MMU
@@ -10739,7 +10820,6 @@ int hush_main(int argc, char **argv)
10739 bb_simple_perror_msg_and_die(G.global_argv[0]); 10820 bb_simple_perror_msg_and_die(G.global_argv[0]);
10740 } 10821 }
10741 xfunc_error_retval = 1; 10822 xfunc_error_retval = 1;
10742 install_special_sighandlers();
10743 parse_and_run_file(input); 10823 parse_and_run_file(input);
10744#if ENABLE_FEATURE_CLEAN_UP 10824#if ENABLE_FEATURE_CLEAN_UP
10745 hfclose(input); 10825 hfclose(input);
@@ -10755,138 +10835,86 @@ int hush_main(int argc, char **argv)
10755 10835
10756 /* A shell is interactive if the '-i' flag was given, 10836 /* A shell is interactive if the '-i' flag was given,
10757 * or if all of the following conditions are met: 10837 * or if all of the following conditions are met:
10758 * no -c command 10838 * not -c 'CMD'
10759 * no arguments remaining or the -s flag given 10839 * not running a script (no arguments remaining, or -s flag given)
10760 * standard input is a terminal 10840 * standard input is a terminal
10761 * standard output is a terminal 10841 * standard output is a terminal
10762 * Refer to Posix.2, the description of the 'sh' utility. 10842 * Refer to Posix.2, the description of the 'sh' utility.
10763 */ 10843 */
10764#if ENABLE_HUSH_JOB 10844#if ENABLE_HUSH_INTERACTIVE
10765 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { 10845 if (!G_reexeced_on_NOMMU
10766 G_saved_tty_pgrp = tcgetpgrp(STDIN_FILENO); 10846 && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)
10767 debug_printf("saved_tty_pgrp:%d\n", G_saved_tty_pgrp); 10847 ) {
10768 if (G_saved_tty_pgrp < 0) 10848 /* Try to dup stdin to high fd#, >= 255 */
10769 G_saved_tty_pgrp = 0;
10770
10771 /* try to dup stdin to high fd#, >= 255 */
10772 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); 10849 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254);
10773 if (G_interactive_fd < 0) { 10850 if (G_interactive_fd < 0) {
10774 /* try to dup to any fd */ 10851 /* Try to dup to any fd */
10775 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1); 10852 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1);
10776 if (G_interactive_fd < 0) { 10853 if (G_interactive_fd < 0)
10777 /* give up */ 10854 /* Give up */
10778 G_interactive_fd = 0; 10855 G_interactive_fd = 0;
10779 G_saved_tty_pgrp = 0;
10780 }
10781 } 10856 }
10782 } 10857 debug_printf("interactive_fd:%d\n", G_interactive_fd);
10783 debug_printf("interactive_fd:%d\n", G_interactive_fd); 10858 if (G_interactive_fd) {
10784 if (G_interactive_fd) { 10859// TODO? bash:
10785 if (G_saved_tty_pgrp) { 10860// if interactive but not a login shell, sources ~/.bashrc
10786 /* If we were run as 'hush &', sleep until we are 10861// (--norc turns this off, --rcfile <file> overrides)
10787 * in the foreground (tty pgrp == our pgrp). 10862# if ENABLE_HUSH_JOB
10788 * If we get started under a job aware app (like bash), 10863 /* Can we do job control? */
10789 * make sure we are now in charge so we don't fight over 10864 G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd);
10790 * who gets the foreground */ 10865 debug_printf("saved_tty_pgrp:%d\n", G_saved_tty_pgrp);
10791 while (1) { 10866 if (G_saved_tty_pgrp < 0)
10792 pid_t shell_pgrp = getpgrp(); 10867 G_saved_tty_pgrp = 0; /* no */
10793 G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd); 10868 if (G_saved_tty_pgrp) {
10794 if (G_saved_tty_pgrp == shell_pgrp) 10869 /* If we were run as 'hush &', sleep until we are
10795 break; 10870 * in the foreground (tty pgrp == our pgrp).
10796 /* send TTIN to ourself (should stop us) */ 10871 * If we get started under a job aware app (like bash),
10797 kill(- shell_pgrp, SIGTTIN); 10872 * make sure we are now in charge so we don't fight over
10873 * who gets the foreground */
10874 while (1) {
10875 pid_t shell_pgrp = getpgrp();
10876 if (G_saved_tty_pgrp == shell_pgrp) {
10877/* Often both pgrps here are set to our pid - but not always!
10878 * Example: sh -c 'echo $$; hush; echo FIN'
10879 * Here, the parent shell is not interactive, so it does NOT set up
10880 * a separate process group for its children, and we (hush) initially
10881 * run in parent's process group (until we set up our own a few lines down).
10882 */
10883 //bb_error_msg("process groups tty:%d hush:%d", G_saved_tty_pgrp, shell_pgrp);
10884 break;
10885 }
10886 /* Send TTIN to ourself (should stop us) */
10887 kill(- shell_pgrp, SIGTTIN);
10888 G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd);
10889 }
10798 } 10890 }
10799 }
10800
10801 /* Install more signal handlers */
10802 install_special_sighandlers();
10803
10804 if (G_saved_tty_pgrp) {
10805 /* Set other signals to restore saved_tty_pgrp */
10806 install_fatal_sighandlers();
10807 /* Put ourselves in our own process group
10808 * (bash, too, does this only if ctty is available) */
10809 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */
10810 /* Grab control of the terminal */
10811 tcsetpgrp(G_interactive_fd, cached_getpid);
10812 }
10813 enable_restore_tty_pgrp_on_exit();
10814
10815# if ENABLE_FEATURE_EDITING
10816 G.line_input_state = new_line_input_t(FOR_SHELL);
10817# if ENABLE_FEATURE_TAB_COMPLETION
10818 G.line_input_state->get_exe_name = hush_command_name;
10819# endif
10820# if EDITING_HAS_sh_get_var
10821 G.line_input_state->sh_get_var = get_local_var_value;
10822# endif
10823# endif 10891# endif
10824# if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 10892 /* Install more signal handlers */
10825 { 10893 install_special_sighandlers();
10826 const char *hp = get_local_var_value("HISTFILE"); 10894# if ENABLE_HUSH_JOB
10827 if (!hp) { 10895 if (G_saved_tty_pgrp) {
10828 hp = get_local_var_value("HOME"); 10896 /* Set fatal signals to restore saved_tty_pgrp */
10829 if (hp) { 10897 install_fatal_sighandlers();
10830 hp = concat_path_file(hp, ".hush_history"); 10898 /* (The if() is an optimization: can avoid two redundant syscalls) */
10831 /* Make HISTFILE set on exit (else history won't be saved) */ 10899 if (G_saved_tty_pgrp != G.root_pid) {
10832 set_local_var_from_halves("HISTFILE", hp); 10900 /* Put ourselves in our own process group
10901 * (bash, too, does this only if ctty is available) */
10902 bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */
10903 /* Grab control of the terminal */
10904 tcsetpgrp(G_interactive_fd, G.root_pid);
10833 } 10905 }
10834 } else {
10835 hp = xstrdup(hp);
10836 } 10906 }
10837 if (hp) {
10838 G.line_input_state->hist_file = hp;
10839 }
10840# if ENABLE_FEATURE_SH_HISTFILESIZE
10841 hp = get_local_var_value("HISTSIZE");
10842 /* Using HISTFILESIZE above to limit max_history would be WRONG:
10843 * users may set HISTFILESIZE=0 in their profile scripts
10844 * to prevent _saving_ of history files, but still want to have
10845 * non-zero history limit for in-memory list.
10846 */
10847// in bash, runtime history size is controlled by HISTSIZE (0=no history),
10848// HISTFILESIZE controls on-disk history file size (in lines, 0=no history):
10849 G.line_input_state->max_history = size_from_HISTFILESIZE(hp);
10850// HISTFILESIZE: "The shell sets the default value to the value of HISTSIZE after reading any startup files."
10851// HISTSIZE: "The shell sets the default value to 500 after reading any startup files."
10852// (meaning: if the value wasn't set after startup files, the default value is set as described above)
10853# endif
10854 }
10855# endif 10907# endif
10856 } else { 10908# if ENABLE_FEATURE_EDITING_FANCY_PROMPT
10857 install_special_sighandlers(); 10909 /* Set (but not export) PS1/2 unless already set */
10858 } 10910 if (!get_local_var_value("PS1"))
10859#elif ENABLE_HUSH_INTERACTIVE 10911 set_local_var_from_halves("PS1", "\\w \\$ ");
10860 /* No job control compiled in, only prompt/line editing */ 10912 if (!get_local_var_value("PS2"))
10861 if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { 10913 set_local_var_from_halves("PS2", "> ");
10862 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); 10914# endif
10863 if (G_interactive_fd < 0) { 10915 init_line_editing();
10864 /* try to dup to any fd */
10865 G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1);
10866 if (G_interactive_fd < 0)
10867 /* give up */
10868 G_interactive_fd = 0;
10869 }
10870 }
10871 install_special_sighandlers();
10872#else
10873 /* We have interactiveness code disabled */
10874 install_special_sighandlers();
10875#endif
10876 /* bash:
10877 * if interactive but not a login shell, sources ~/.bashrc
10878 * (--norc turns this off, --rcfile <file> overrides)
10879 */
10880 10916
10881 if (G_interactive_fd) { 10917# if !ENABLE_FEATURE_SH_EXTRA_QUIET
10882#if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT
10883 /* Set (but not export) PS1/2 unless already set */
10884 if (!get_local_var_value("PS1"))
10885 set_local_var_from_halves("PS1", "\\w \\$ ");
10886 if (!get_local_var_value("PS2"))
10887 set_local_var_from_halves("PS2", "> ");
10888#endif
10889 if (!ENABLE_FEATURE_SH_EXTRA_QUIET) {
10890 /* note: ash and hush share this string */ 10918 /* note: ash and hush share this string */
10891 printf("\n\n%s %s\n" 10919 printf("\n\n%s %s\n"
10892 IF_HUSH_HELP("Enter 'help' for a list of built-in commands.\n") 10920 IF_HUSH_HELP("Enter 'help' for a list of built-in commands.\n")
@@ -10894,13 +10922,15 @@ int hush_main(int argc, char **argv)
10894 bb_banner, 10922 bb_banner,
10895 "hush - the humble shell" 10923 "hush - the humble shell"
10896 ); 10924 );
10897 } 10925# endif
10898 } 10926 } /* if become interactive */
10927 } /* if on tty */
10928#endif /* if INTERACTIVE is allowed by build config */
10899 10929
10900 parse_and_run_file(hfopen(NULL)); /* stdin */ 10930 parse_and_run_file(hfopen(NULL)); /* stdin */
10901 10931
10902 final_return: 10932 final_return:
10903 hush_exit(G.last_exitcode); 10933 save_history_run_exit_trap_and_exit(G.last_exitcode);
10904} 10934}
10905 10935
10906/* 10936/*
@@ -11086,19 +11116,19 @@ static int FAST_FUNC builtin_exit(char **argv)
11086 * TODO: we can use G.exiting = -1 as indicator "last cmd was exit" 11116 * TODO: we can use G.exiting = -1 as indicator "last cmd was exit"
11087 */ 11117 */
11088 11118
11089 /* note: EXIT trap is run by hush_exit */ 11119 /* note: EXIT trap is run by save_history_run_exit_trap_and_exit */
11090 argv = skip_dash_dash(argv); 11120 argv = skip_dash_dash(argv);
11091 if (argv[0] == NULL) { 11121 if (argv[0] == NULL) {
11092#if ENABLE_HUSH_TRAP 11122#if ENABLE_HUSH_TRAP
11093 if (G.pre_trap_exitcode >= 0) /* "exit" in trap uses $? from before the trap */ 11123 if (G.pre_trap_exitcode >= 0) /* "exit" in trap uses $? from before the trap */
11094 hush_exit(G.pre_trap_exitcode); 11124 save_history_run_exit_trap_and_exit(G.pre_trap_exitcode);
11095#endif 11125#endif
11096 hush_exit(G.last_exitcode); 11126 save_history_run_exit_trap_and_exit(G.last_exitcode);
11097 } 11127 }
11098 /* mimic bash: exit 123abc == exit 255 + error msg */ 11128 /* mimic bash: exit 123abc == exit 255 + error msg */
11099 xfunc_error_retval = 255; 11129 xfunc_error_retval = 255;
11100 /* bash: exit -2 == exit 254, no error msg */ 11130 /* bash: exit -2 == exit 254, no error msg */
11101 hush_exit(xatoi(argv[0]) & 0xff); 11131 save_history_run_exit_trap_and_exit(xatoi(argv[0]) & 0xff);
11102} 11132}
11103 11133
11104#if ENABLE_HUSH_TYPE 11134#if ENABLE_HUSH_TYPE