diff options
Diffstat (limited to '')
-rw-r--r-- | shell/hush.c | 468 |
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) | |||
1352 | static void *xxmalloc(int lineno, size_t size) | 1360 | static 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 | } | ||
1366 | static 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 | } |
1358 | static void *xxrealloc(int lineno, void *ptr, size_t size) | 1372 | static 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 | } | ||
1380 | static 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 | } |
1364 | static char *xxstrdup(int lineno, const char *str) | 1388 | static 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 | } | ||
1394 | static 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 | } | ||
1400 | static 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 | } |
1370 | static void xxfree(void *ptr) | 1411 | static 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 | ||
2005 | static void hush_exit(int exitcode) NORETURN; | ||
2006 | |||
2007 | static void restore_ttypgrp_and__exit(void) NORETURN; | ||
2008 | static 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 | */ |
2031 | static void fflush_and__exit(void) NORETURN; | 2063 | static NORETURN void fflush_and__exit(void) |
2032 | static 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 | */ |
2049 | static void sigexit(int sig) NORETURN; | 2076 | static NORETURN void restore_ttypgrp_and_killsig_or__exit(int sig) |
2050 | static 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 | |||
2095 | static 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 | ||
2102 | static const char* FAST_FUNC get_local_var_value(const char *name); | 2141 | static const char* FAST_FUNC get_local_var_value(const char *name); |
2103 | 2142 | ||
2104 | /* Restores tty foreground process group, and exits. */ | 2143 | /* Self-explanatory. |
2105 | static void hush_exit(int exitcode) | 2144 | * Restores tty foreground process group too. |
2145 | */ | ||
2146 | static 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 */ | ||
7388 | void re_execute_shell(char ***to_free, const char *s, | ||
7389 | char *g_argv0, char **g_argv, | ||
7390 | char **builtin_argv) NORETURN; | ||
7391 | |||
7392 | static void reset_traps_to_defaults(void) | 7435 | static 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 | ||
7441 | static void re_execute_shell(char ***to_free, const char *s, | 7484 | static 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; | ||
7444 | static 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 |
8297 | static const char * FAST_FUNC hush_command_name(int i) | 8344 | static 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 |
8462 | static void exec_function(char ***to_free, | 8509 | static NORETURN void exec_function( |
8463 | const struct function *funcp, | 8510 | char * *volatile *to_free, |
8464 | char **argv) NORETURN; | ||
8465 | static 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 |
8561 | static void exec_builtin(char ***to_free, | 8606 | static NORETURN void exec_builtin( |
8562 | const struct built_in_command *x, | 8607 | char * *volatile *to_free, |
8563 | char **argv) NORETURN; | ||
8564 | static 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 | ||
8587 | static void execvp_or_die(char **argv) NORETURN; | 8630 | static NORETURN void execvp_or_die(char **argv) |
8588 | static 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 | */ |
8709 | static void pseudo_exec_argv(nommu_save_t *nommu_save, | 8751 | static NORETURN NOINLINE void pseudo_exec_argv( |
8710 | char **argv, int assignment_cnt, | 8752 | volatile nommu_save_t *nommu_save, |
8711 | char **argv_expanded) NORETURN; | ||
8712 | static 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 | */ |
8865 | static void pseudo_exec(nommu_save_t *nommu_save, | 8906 | static NORETURN void pseudo_exec( |
8866 | struct command *command, | 8907 | volatile nommu_save_t *nommu_save, |
8867 | char **argv_expanded) NORETURN; | ||
8868 | static 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 | ||
10255 | static 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 | |||
10216 | static void install_sighandlers(unsigned mask) | 10301 | static 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) | |||
10351 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 10436 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
10352 | int hush_main(int argc, char **argv) | 10437 | int 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 |