diff options
Diffstat (limited to '')
-rw-r--r-- | shell/ash.c | 15 | ||||
-rw-r--r-- | shell/hush.c | 463 | ||||
-rwxr-xr-x | shell/hush_leaktool.sh | 18 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/sig_exitcode.tests | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/wait1.tests | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/wait2.tests | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/wait3.tests | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/wait4.tests | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/wait5.tests | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/wait6.tests | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-signals/catch.tests | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-signals/signal1.tests | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-signals/signal8.tests | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-signals/signal_read2.tests | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-signals/subshell.tests | 3 | ||||
-rwxr-xr-x | shell/hush_test/run-all | 7 |
16 files changed, 302 insertions, 237 deletions
diff --git a/shell/ash.c b/shell/ash.c index 0038aa1e9..605215e41 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -461,7 +461,7 @@ static void forkshell_print(FILE *fp0, struct forkshell *fs, const char **notes) | |||
461 | 461 | ||
462 | /* ============ Shell options */ | 462 | /* ============ Shell options */ |
463 | 463 | ||
464 | /* If you add/change options hare, update --help text too */ | 464 | /* If you add/change options here, update --help text too */ |
465 | static const char *const optletters_optnames[] ALIGN_PTR = { | 465 | static const char *const optletters_optnames[] ALIGN_PTR = { |
466 | "e" "errexit", | 466 | "e" "errexit", |
467 | "f" "noglob", | 467 | "f" "noglob", |
@@ -1822,7 +1822,6 @@ struct stackmark { | |||
1822 | size_t stacknleft; | 1822 | size_t stacknleft; |
1823 | }; | 1823 | }; |
1824 | 1824 | ||
1825 | |||
1826 | struct globals_memstack { | 1825 | struct globals_memstack { |
1827 | struct stack_block *g_stackp; // = &stackbase; | 1826 | struct stack_block *g_stackp; // = &stackbase; |
1828 | char *g_stacknxt; // = stackbase.space; | 1827 | char *g_stacknxt; // = stackbase.space; |
@@ -1845,7 +1844,6 @@ extern struct globals_memstack *BB_GLOBAL_CONST ash_ptr_to_globals_memstack; | |||
1845 | sstrend = stackbase.space + MINSIZE; \ | 1844 | sstrend = stackbase.space + MINSIZE; \ |
1846 | } while (0) | 1845 | } while (0) |
1847 | 1846 | ||
1848 | |||
1849 | #define stackblock() ((void *)g_stacknxt) | 1847 | #define stackblock() ((void *)g_stacknxt) |
1850 | #define stackblocksize() g_stacknleft | 1848 | #define stackblocksize() g_stacknleft |
1851 | 1849 | ||
@@ -2362,7 +2360,6 @@ struct localvar { | |||
2362 | # define VIMPORT 0x400 /* variable was imported from environment */ | 2360 | # define VIMPORT 0x400 /* variable was imported from environment */ |
2363 | #endif | 2361 | #endif |
2364 | 2362 | ||
2365 | |||
2366 | /* Need to be before varinit_data[] */ | 2363 | /* Need to be before varinit_data[] */ |
2367 | #if ENABLE_LOCALE_SUPPORT | 2364 | #if ENABLE_LOCALE_SUPPORT |
2368 | static void FAST_FUNC | 2365 | static void FAST_FUNC |
@@ -3582,7 +3579,6 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
3582 | 3579 | ||
3583 | /* ============ ... */ | 3580 | /* ============ ... */ |
3584 | 3581 | ||
3585 | |||
3586 | #define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024) | 3582 | #define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024) |
3587 | 3583 | ||
3588 | /* Syntax classes */ | 3584 | /* Syntax classes */ |
@@ -3989,13 +3985,11 @@ struct alias { | |||
3989 | int flag; | 3985 | int flag; |
3990 | }; | 3986 | }; |
3991 | 3987 | ||
3992 | |||
3993 | static struct alias **atab; // [ATABSIZE]; | 3988 | static struct alias **atab; // [ATABSIZE]; |
3994 | #define INIT_G_alias() do { \ | 3989 | #define INIT_G_alias() do { \ |
3995 | atab = xzalloc(ATABSIZE * sizeof(atab[0])); \ | 3990 | atab = xzalloc(ATABSIZE * sizeof(atab[0])); \ |
3996 | } while (0) | 3991 | } while (0) |
3997 | 3992 | ||
3998 | |||
3999 | static struct alias ** | 3993 | static struct alias ** |
4000 | __lookupalias(const char *name) | 3994 | __lookupalias(const char *name) |
4001 | { | 3995 | { |
@@ -4177,7 +4171,6 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
4177 | 4171 | ||
4178 | #endif /* ASH_ALIAS */ | 4172 | #endif /* ASH_ALIAS */ |
4179 | 4173 | ||
4180 | |||
4181 | /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ | 4174 | /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ |
4182 | #define FORK_FG 0 | 4175 | #define FORK_FG 0 |
4183 | #define FORK_BG 1 | 4176 | #define FORK_BG 1 |
@@ -6194,7 +6187,6 @@ stoppedjobs(void) | |||
6194 | } | 6187 | } |
6195 | #endif | 6188 | #endif |
6196 | 6189 | ||
6197 | |||
6198 | /* | 6190 | /* |
6199 | * Code for dealing with input/output redirection. | 6191 | * Code for dealing with input/output redirection. |
6200 | */ | 6192 | */ |
@@ -9904,7 +9896,6 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
9904 | } | 9896 | } |
9905 | #endif | 9897 | #endif |
9906 | 9898 | ||
9907 | |||
9908 | /*static int funcblocksize; // size of structures in function */ | 9899 | /*static int funcblocksize; // size of structures in function */ |
9909 | /*static int funcstringsize; // size of strings in node */ | 9900 | /*static int funcstringsize; // size of strings in node */ |
9910 | static void *funcblock; /* block to allocate function from */ | 9901 | static void *funcblock; /* block to allocate function from */ |
@@ -11920,7 +11911,6 @@ goodname(const char *p) | |||
11920 | return endofname(p)[0] == '\0'; | 11911 | return endofname(p)[0] == '\0'; |
11921 | } | 11912 | } |
11922 | 11913 | ||
11923 | |||
11924 | /* | 11914 | /* |
11925 | * Search for a command. This is called before we fork so that the | 11915 | * Search for a command. This is called before we fork so that the |
11926 | * location of the command will be available in the parent as well as | 11916 | * location of the command will be available in the parent as well as |
@@ -14773,7 +14763,6 @@ parseheredoc(void) | |||
14773 | } | 14763 | } |
14774 | } | 14764 | } |
14775 | 14765 | ||
14776 | |||
14777 | static const char * | 14766 | static const char * |
14778 | expandstr(const char *ps, int syntax_type) | 14767 | expandstr(const char *ps, int syntax_type) |
14779 | { | 14768 | { |
@@ -15403,7 +15392,6 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
15403 | entry->u = cmdp->param; | 15392 | entry->u = cmdp->param; |
15404 | } | 15393 | } |
15405 | 15394 | ||
15406 | |||
15407 | /* | 15395 | /* |
15408 | * The trap builtin. | 15396 | * The trap builtin. |
15409 | */ | 15397 | */ |
@@ -16170,7 +16158,6 @@ init(void) | |||
16170 | } | 16158 | } |
16171 | } | 16159 | } |
16172 | 16160 | ||
16173 | |||
16174 | //usage:#define ash_trivial_usage | 16161 | //usage:#define ash_trivial_usage |
16175 | //usage: "[-il] [-|+Cabefmnuvx] [-|+o OPT]... [-c 'SCRIPT' [ARG0 ARGS] | FILE ARGS | -s ARGS]" | 16162 | //usage: "[-il] [-|+Cabefmnuvx] [-|+o OPT]... [-c 'SCRIPT' [ARG0 ARGS] | FILE ARGS | -s ARGS]" |
16176 | //////// comes from ^^^^^^^^^^optletters | 16163 | //////// comes from ^^^^^^^^^^optletters |
diff --git a/shell/hush.c b/shell/hush.c index d1f687f9d..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 |
@@ -7389,11 +7432,6 @@ static void switch_off_special_sigs(unsigned mask) | |||
7389 | } | 7432 | } |
7390 | 7433 | ||
7391 | #if BB_MMU | 7434 | #if BB_MMU |
7392 | /* never called */ | ||
7393 | void re_execute_shell(char ***to_free, const char *s, | ||
7394 | char *g_argv0, char **g_argv, | ||
7395 | char **builtin_argv) NORETURN; | ||
7396 | |||
7397 | static void reset_traps_to_defaults(void) | 7435 | static void reset_traps_to_defaults(void) |
7398 | { | 7436 | { |
7399 | /* This function is always called in a child shell | 7437 | /* This function is always called in a child shell |
@@ -7443,10 +7481,8 @@ static void reset_traps_to_defaults(void) | |||
7443 | 7481 | ||
7444 | #else /* !BB_MMU */ | 7482 | #else /* !BB_MMU */ |
7445 | 7483 | ||
7446 | static void re_execute_shell(char ***to_free, const char *s, | 7484 | static NORETURN void re_execute_shell( |
7447 | char *g_argv0, char **g_argv, | 7485 | char * *volatile * to_free, const char *s, |
7448 | char **builtin_argv) NORETURN; | ||
7449 | static void re_execute_shell(char ***to_free, const char *s, | ||
7450 | char *g_argv0, char **g_argv, | 7486 | char *g_argv0, char **g_argv, |
7451 | char **builtin_argv) | 7487 | char **builtin_argv) |
7452 | { | 7488 | { |
@@ -7676,7 +7712,13 @@ static int generate_stream_from_string(const char *s, pid_t *pid_p) | |||
7676 | pid_t pid; | 7712 | pid_t pid; |
7677 | int channel[2]; | 7713 | int channel[2]; |
7678 | # if !BB_MMU | 7714 | # if !BB_MMU |
7679 | 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; | ||
7680 | # endif | 7722 | # endif |
7681 | 7723 | ||
7682 | xpipe(channel); | 7724 | xpipe(channel); |
@@ -7823,7 +7865,7 @@ static void setup_heredoc(struct redir_struct *redir) | |||
7823 | const char *heredoc = redir->rd_filename; | 7865 | const char *heredoc = redir->rd_filename; |
7824 | char *expanded; | 7866 | char *expanded; |
7825 | #if !BB_MMU | 7867 | #if !BB_MMU |
7826 | char **to_free; | 7868 | char * *volatile to_free; |
7827 | #endif | 7869 | #endif |
7828 | 7870 | ||
7829 | expanded = NULL; | 7871 | expanded = NULL; |
@@ -8298,7 +8340,7 @@ static const struct built_in_command *find_builtin(const char *name) | |||
8298 | return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]); | 8340 | return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]); |
8299 | } | 8341 | } |
8300 | 8342 | ||
8301 | #if ENABLE_HUSH_JOB && ENABLE_FEATURE_TAB_COMPLETION | 8343 | #if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_TAB_COMPLETION |
8302 | static const char * FAST_FUNC hush_command_name(int i) | 8344 | static const char * FAST_FUNC hush_command_name(int i) |
8303 | { | 8345 | { |
8304 | if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) { | 8346 | if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) { |
@@ -8464,10 +8506,8 @@ static void unset_func(const char *name) | |||
8464 | #define exec_function(to_free, funcp, argv) \ | 8506 | #define exec_function(to_free, funcp, argv) \ |
8465 | exec_function(funcp, argv) | 8507 | exec_function(funcp, argv) |
8466 | # endif | 8508 | # endif |
8467 | static void exec_function(char ***to_free, | 8509 | static NORETURN void exec_function( |
8468 | const struct function *funcp, | 8510 | char * *volatile *to_free, |
8469 | char **argv) NORETURN; | ||
8470 | static void exec_function(char ***to_free, | ||
8471 | const struct function *funcp, | 8511 | const struct function *funcp, |
8472 | char **argv) | 8512 | char **argv) |
8473 | { | 8513 | { |
@@ -8563,10 +8603,8 @@ static int run_function(const struct function *funcp, char **argv) | |||
8563 | #define exec_builtin(to_free, x, argv) \ | 8603 | #define exec_builtin(to_free, x, argv) \ |
8564 | exec_builtin(to_free, argv) | 8604 | exec_builtin(to_free, argv) |
8565 | #endif | 8605 | #endif |
8566 | static void exec_builtin(char ***to_free, | 8606 | static NORETURN void exec_builtin( |
8567 | const struct built_in_command *x, | 8607 | char * *volatile *to_free, |
8568 | char **argv) NORETURN; | ||
8569 | static void exec_builtin(char ***to_free, | ||
8570 | const struct built_in_command *x, | 8608 | const struct built_in_command *x, |
8571 | char **argv) | 8609 | char **argv) |
8572 | { | 8610 | { |
@@ -8589,8 +8627,7 @@ static void exec_builtin(char ***to_free, | |||
8589 | #endif | 8627 | #endif |
8590 | } | 8628 | } |
8591 | 8629 | ||
8592 | static void execvp_or_die(char **argv) NORETURN; | 8630 | static NORETURN void execvp_or_die(char **argv) |
8593 | static void execvp_or_die(char **argv) | ||
8594 | { | 8631 | { |
8595 | int e; | 8632 | int e; |
8596 | debug_printf_exec("execing '%s'\n", argv[0]); | 8633 | debug_printf_exec("execing '%s'\n", argv[0]); |
@@ -8711,10 +8748,8 @@ static void if_command_vV_print_and_exit(char opt_vV, char *cmd, const char *exp | |||
8711 | * The at_exit handlers apparently confuse the calling process, | 8748 | * The at_exit handlers apparently confuse the calling process, |
8712 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) | 8749 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) |
8713 | */ | 8750 | */ |
8714 | static void pseudo_exec_argv(nommu_save_t *nommu_save, | 8751 | static NORETURN NOINLINE void pseudo_exec_argv( |
8715 | char **argv, int assignment_cnt, | 8752 | volatile nommu_save_t *nommu_save, |
8716 | char **argv_expanded) NORETURN; | ||
8717 | static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | ||
8718 | char **argv, int assignment_cnt, | 8753 | char **argv, int assignment_cnt, |
8719 | char **argv_expanded) | 8754 | char **argv_expanded) |
8720 | { | 8755 | { |
@@ -8740,7 +8775,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
8740 | #if BB_MMU | 8775 | #if BB_MMU |
8741 | G.shadowed_vars_pp = NULL; /* "don't save, free them instead" */ | 8776 | G.shadowed_vars_pp = NULL; /* "don't save, free them instead" */ |
8742 | #else | 8777 | #else |
8743 | G.shadowed_vars_pp = &nommu_save->old_vars; | 8778 | /* cast away volatility */ |
8779 | G.shadowed_vars_pp = (struct variable **)&nommu_save->old_vars; | ||
8744 | G.var_nest_level++; | 8780 | G.var_nest_level++; |
8745 | #endif | 8781 | #endif |
8746 | set_vars_and_save_old(new_env); | 8782 | set_vars_and_save_old(new_env); |
@@ -8867,10 +8903,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
8867 | 8903 | ||
8868 | /* Called after [v]fork() in run_pipe | 8904 | /* Called after [v]fork() in run_pipe |
8869 | */ | 8905 | */ |
8870 | static void pseudo_exec(nommu_save_t *nommu_save, | 8906 | static NORETURN void pseudo_exec( |
8871 | struct command *command, | 8907 | volatile nommu_save_t *nommu_save, |
8872 | char **argv_expanded) NORETURN; | ||
8873 | static void pseudo_exec(nommu_save_t *nommu_save, | ||
8874 | struct command *command, | 8908 | struct command *command, |
8875 | char **argv_expanded) | 8909 | char **argv_expanded) |
8876 | { | 8910 | { |
@@ -9755,8 +9789,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
9755 | 9789 | ||
9756 | /* Stores to nommu_save list of env vars putenv'ed | 9790 | /* Stores to nommu_save list of env vars putenv'ed |
9757 | * (NOMMU, on MMU we don't need that) */ | 9791 | * (NOMMU, on MMU we don't need that) */ |
9758 | /* cast away volatility... */ | 9792 | pseudo_exec(&nommu_save, command, argv_expanded); |
9759 | pseudo_exec((nommu_save_t*) &nommu_save, command, argv_expanded); | ||
9760 | /* pseudo_exec() does not return */ | 9793 | /* pseudo_exec() does not return */ |
9761 | } | 9794 | } |
9762 | 9795 | ||
@@ -10144,7 +10177,7 @@ static int run_list(struct pipe *pi) | |||
10144 | if (rcode != 0 && G.o_opt[OPT_O_ERREXIT]) { | 10177 | if (rcode != 0 && G.o_opt[OPT_O_ERREXIT]) { |
10145 | 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); |
10146 | if (G.errexit_depth == 0) | 10179 | if (G.errexit_depth == 0) |
10147 | hush_exit(rcode); | 10180 | save_history_run_exit_trap_and_exit(rcode); |
10148 | } | 10181 | } |
10149 | G.errexit_depth = sv_errexit_depth; | 10182 | G.errexit_depth = sv_errexit_depth; |
10150 | 10183 | ||
@@ -10218,6 +10251,53 @@ static int run_and_free_list(struct pipe *pi) | |||
10218 | /* | 10251 | /* |
10219 | * Initialization and main | 10252 | * Initialization and main |
10220 | */ | 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 | |||
10221 | static void install_sighandlers(unsigned mask) | 10301 | static void install_sighandlers(unsigned mask) |
10222 | { | 10302 | { |
10223 | sighandler_t old_handler; | 10303 | sighandler_t old_handler; |
@@ -10356,7 +10436,6 @@ static int set_mode(int state, char mode, const char *o_opt) | |||
10356 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 10436 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
10357 | int hush_main(int argc, char **argv) | 10437 | int hush_main(int argc, char **argv) |
10358 | { | 10438 | { |
10359 | pid_t cached_getpid; | ||
10360 | enum { | 10439 | enum { |
10361 | OPT_login = (1 << 0), | 10440 | OPT_login = (1 << 0), |
10362 | }; | 10441 | }; |
@@ -10369,6 +10448,11 @@ int hush_main(int argc, char **argv) | |||
10369 | struct variable *shell_ver; | 10448 | struct variable *shell_ver; |
10370 | 10449 | ||
10371 | 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 | ||
10372 | 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 */ |
10373 | G.last_exitcode = EXIT_SUCCESS; | 10457 | G.last_exitcode = EXIT_SUCCESS; |
10374 | #if !BB_MMU | 10458 | #if !BB_MMU |
@@ -10384,9 +10468,6 @@ int hush_main(int argc, char **argv) | |||
10384 | _exit(0); | 10468 | _exit(0); |
10385 | } | 10469 | } |
10386 | G.argv0_for_re_execing = argv[0]; | 10470 | G.argv0_for_re_execing = argv[0]; |
10387 | if (G.argv0_for_re_execing[0] == '-') | ||
10388 | /* reexeced hush should never be a login shell */ | ||
10389 | G.argv0_for_re_execing++; | ||
10390 | #endif | 10471 | #endif |
10391 | #if ENABLE_HUSH_TRAP | 10472 | #if ENABLE_HUSH_TRAP |
10392 | # if ENABLE_HUSH_FUNCTIONS | 10473 | # if ENABLE_HUSH_FUNCTIONS |
@@ -10399,9 +10480,8 @@ int hush_main(int argc, char **argv) | |||
10399 | G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ | 10480 | G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ |
10400 | #endif | 10481 | #endif |
10401 | 10482 | ||
10402 | cached_getpid = getpid(); /* for tcsetpgrp() during init */ | 10483 | G.root_pid = getpid(); /* for $PID (NOMMU can override via -$HEXPID:HEXPPID:...) */ |
10403 | G.root_pid = cached_getpid; /* for $PID (NOMMU can override via -$HEXPID:HEXPPID:...) */ | 10484 | G.root_ppid = getppid(); /* for $PPID (NOMMU can override) */ |
10404 | G.root_ppid = getppid(); /* for $PPID (NOMMU can override) */ | ||
10405 | 10485 | ||
10406 | /* Deal with HUSH_VERSION */ | 10486 | /* Deal with HUSH_VERSION */ |
10407 | debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); | 10487 | debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); |
@@ -10484,27 +10564,24 @@ int hush_main(int argc, char **argv) | |||
10484 | * PS4='+ ' | 10564 | * PS4='+ ' |
10485 | */ | 10565 | */ |
10486 | 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 | |||
10487 | #if NUM_SCRIPTS > 0 | 10575 | #if NUM_SCRIPTS > 0 |
10488 | if (argc < 0) { | 10576 | if (argc < 0) { |
10489 | char *script = get_script_content(-argc - 1); | 10577 | char *script = get_script_content(-argc - 1); |
10490 | G.global_argv = argv; | 10578 | G.global_argv = argv; |
10491 | G.global_argc = string_array_len(argv); | 10579 | G.global_argc = string_array_len(argv); |
10492 | //install_special_sighandlers(); - needed? | ||
10493 | parse_and_run_string(script); | 10580 | parse_and_run_string(script); |
10494 | goto final_return; | 10581 | goto final_return; |
10495 | } | 10582 | } |
10496 | #endif | 10583 | #endif |
10497 | 10584 | ||
10498 | /* Initialize some more globals to non-zero values */ | ||
10499 | die_func = restore_ttypgrp_and__exit; | ||
10500 | |||
10501 | /* Shell is non-interactive at first. We need to call | ||
10502 | * install_special_sighandlers() if we are going to execute "sh <script>", | ||
10503 | * "sh -c <cmds>" or login shell's /etc/profile and friends. | ||
10504 | * If we later decide that we are interactive, we run install_special_sighandlers() | ||
10505 | * in order to intercept (more) signals. | ||
10506 | */ | ||
10507 | |||
10508 | /* Parse options */ | 10585 | /* Parse options */ |
10509 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ | 10586 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ |
10510 | flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; | 10587 | flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; |
@@ -10568,6 +10645,7 @@ int hush_main(int argc, char **argv) | |||
10568 | case '$': { | 10645 | case '$': { |
10569 | unsigned long long empty_trap_mask; | 10646 | unsigned long long empty_trap_mask; |
10570 | 10647 | ||
10648 | G.reexeced_on_NOMMU = 1; | ||
10571 | G.root_pid = bb_strtou(optarg, &optarg, 16); | 10649 | G.root_pid = bb_strtou(optarg, &optarg, 16); |
10572 | optarg++; | 10650 | optarg++; |
10573 | G.root_ppid = bb_strtou(optarg, &optarg, 16); | 10651 | G.root_ppid = bb_strtou(optarg, &optarg, 16); |
@@ -10581,7 +10659,6 @@ int hush_main(int argc, char **argv) | |||
10581 | empty_trap_mask = bb_strtoull(optarg, &optarg, 16); | 10659 | empty_trap_mask = bb_strtoull(optarg, &optarg, 16); |
10582 | if (empty_trap_mask != 0) { | 10660 | if (empty_trap_mask != 0) { |
10583 | IF_HUSH_TRAP(int sig;) | 10661 | IF_HUSH_TRAP(int sig;) |
10584 | install_special_sighandlers(); | ||
10585 | # if ENABLE_HUSH_TRAP | 10662 | # if ENABLE_HUSH_TRAP |
10586 | G_traps = xzalloc(sizeof(G_traps[0]) * NSIG); | 10663 | G_traps = xzalloc(sizeof(G_traps[0]) * NSIG); |
10587 | for (sig = 1; sig < NSIG; sig++) { | 10664 | for (sig = 1; sig < NSIG; sig++) { |
@@ -10647,7 +10724,9 @@ int hush_main(int argc, char **argv) | |||
10647 | G.global_argv[0] = argv[0]; | 10724 | G.global_argv[0] = argv[0]; |
10648 | 10725 | ||
10649 | /* If we are login shell... */ | 10726 | /* If we are login shell... */ |
10650 | if (flags & OPT_login) { | 10727 | if (!G_reexeced_on_NOMMU /* reexeced hush should never be a login shell */ |
10728 | && (flags & OPT_login) | ||
10729 | ) { | ||
10651 | const char *hp = NULL; | 10730 | const char *hp = NULL; |
10652 | HFILE *input; | 10731 | HFILE *input; |
10653 | 10732 | ||
@@ -10655,7 +10734,6 @@ int hush_main(int argc, char **argv) | |||
10655 | input = hfopen("/etc/profile"); | 10734 | input = hfopen("/etc/profile"); |
10656 | run_profile: | 10735 | run_profile: |
10657 | if (input != NULL) { | 10736 | if (input != NULL) { |
10658 | install_special_sighandlers(); | ||
10659 | parse_and_run_file(input); | 10737 | parse_and_run_file(input); |
10660 | hfclose(input); | 10738 | hfclose(input); |
10661 | } | 10739 | } |
@@ -10692,8 +10770,6 @@ int hush_main(int argc, char **argv) | |||
10692 | */ | 10770 | */ |
10693 | char *script; | 10771 | char *script; |
10694 | 10772 | ||
10695 | install_special_sighandlers(); | ||
10696 | |||
10697 | G.global_argc--; | 10773 | G.global_argc--; |
10698 | G.global_argv++; | 10774 | G.global_argv++; |
10699 | #if !BB_MMU | 10775 | #if !BB_MMU |
@@ -10744,7 +10820,6 @@ int hush_main(int argc, char **argv) | |||
10744 | bb_simple_perror_msg_and_die(G.global_argv[0]); | 10820 | bb_simple_perror_msg_and_die(G.global_argv[0]); |
10745 | } | 10821 | } |
10746 | xfunc_error_retval = 1; | 10822 | xfunc_error_retval = 1; |
10747 | install_special_sighandlers(); | ||
10748 | parse_and_run_file(input); | 10823 | parse_and_run_file(input); |
10749 | #if ENABLE_FEATURE_CLEAN_UP | 10824 | #if ENABLE_FEATURE_CLEAN_UP |
10750 | hfclose(input); | 10825 | hfclose(input); |
@@ -10760,138 +10835,86 @@ int hush_main(int argc, char **argv) | |||
10760 | 10835 | ||
10761 | /* A shell is interactive if the '-i' flag was given, | 10836 | /* A shell is interactive if the '-i' flag was given, |
10762 | * or if all of the following conditions are met: | 10837 | * or if all of the following conditions are met: |
10763 | * no -c command | 10838 | * not -c 'CMD' |
10764 | * no arguments remaining or the -s flag given | 10839 | * not running a script (no arguments remaining, or -s flag given) |
10765 | * standard input is a terminal | 10840 | * standard input is a terminal |
10766 | * standard output is a terminal | 10841 | * standard output is a terminal |
10767 | * Refer to Posix.2, the description of the 'sh' utility. | 10842 | * Refer to Posix.2, the description of the 'sh' utility. |
10768 | */ | 10843 | */ |
10769 | #if ENABLE_HUSH_JOB | 10844 | #if ENABLE_HUSH_INTERACTIVE |
10770 | if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { | 10845 | if (!G_reexeced_on_NOMMU |
10771 | G_saved_tty_pgrp = tcgetpgrp(STDIN_FILENO); | 10846 | && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) |
10772 | debug_printf("saved_tty_pgrp:%d\n", G_saved_tty_pgrp); | 10847 | ) { |
10773 | if (G_saved_tty_pgrp < 0) | 10848 | /* Try to dup stdin to high fd#, >= 255 */ |
10774 | G_saved_tty_pgrp = 0; | ||
10775 | |||
10776 | /* try to dup stdin to high fd#, >= 255 */ | ||
10777 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); | 10849 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); |
10778 | if (G_interactive_fd < 0) { | 10850 | if (G_interactive_fd < 0) { |
10779 | /* try to dup to any fd */ | 10851 | /* Try to dup to any fd */ |
10780 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1); | 10852 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1); |
10781 | if (G_interactive_fd < 0) { | 10853 | if (G_interactive_fd < 0) |
10782 | /* give up */ | 10854 | /* Give up */ |
10783 | G_interactive_fd = 0; | 10855 | G_interactive_fd = 0; |
10784 | G_saved_tty_pgrp = 0; | ||
10785 | } | ||
10786 | } | 10856 | } |
10787 | } | 10857 | debug_printf("interactive_fd:%d\n", G_interactive_fd); |
10788 | debug_printf("interactive_fd:%d\n", G_interactive_fd); | 10858 | if (G_interactive_fd) { |
10789 | if (G_interactive_fd) { | 10859 | // TODO? bash: |
10790 | if (G_saved_tty_pgrp) { | 10860 | // if interactive but not a login shell, sources ~/.bashrc |
10791 | /* If we were run as 'hush &', sleep until we are | 10861 | // (--norc turns this off, --rcfile <file> overrides) |
10792 | * in the foreground (tty pgrp == our pgrp). | 10862 | # if ENABLE_HUSH_JOB |
10793 | * If we get started under a job aware app (like bash), | 10863 | /* Can we do job control? */ |
10794 | * make sure we are now in charge so we don't fight over | 10864 | G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd); |
10795 | * who gets the foreground */ | 10865 | debug_printf("saved_tty_pgrp:%d\n", G_saved_tty_pgrp); |
10796 | while (1) { | 10866 | if (G_saved_tty_pgrp < 0) |
10797 | pid_t shell_pgrp = getpgrp(); | 10867 | G_saved_tty_pgrp = 0; /* no */ |
10798 | G_saved_tty_pgrp = tcgetpgrp(G_interactive_fd); | 10868 | if (G_saved_tty_pgrp) { |
10799 | if (G_saved_tty_pgrp == shell_pgrp) | 10869 | /* If we were run as 'hush &', sleep until we are |
10800 | break; | 10870 | * in the foreground (tty pgrp == our pgrp). |
10801 | /* send TTIN to ourself (should stop us) */ | 10871 | * If we get started under a job aware app (like bash), |
10802 | 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 | } | ||
10803 | } | 10890 | } |
10804 | } | ||
10805 | |||
10806 | /* Install more signal handlers */ | ||
10807 | install_special_sighandlers(); | ||
10808 | |||
10809 | if (G_saved_tty_pgrp) { | ||
10810 | /* Set other signals to restore saved_tty_pgrp */ | ||
10811 | install_fatal_sighandlers(); | ||
10812 | /* Put ourselves in our own process group | ||
10813 | * (bash, too, does this only if ctty is available) */ | ||
10814 | bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ | ||
10815 | /* Grab control of the terminal */ | ||
10816 | tcsetpgrp(G_interactive_fd, cached_getpid); | ||
10817 | } | ||
10818 | enable_restore_tty_pgrp_on_exit(); | ||
10819 | |||
10820 | # if ENABLE_FEATURE_EDITING | ||
10821 | G.line_input_state = new_line_input_t(FOR_SHELL); | ||
10822 | # if ENABLE_FEATURE_TAB_COMPLETION | ||
10823 | G.line_input_state->get_exe_name = hush_command_name; | ||
10824 | # endif | ||
10825 | # if EDITING_HAS_sh_get_var | ||
10826 | G.line_input_state->sh_get_var = get_local_var_value; | ||
10827 | # endif | ||
10828 | # endif | 10891 | # endif |
10829 | # if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 | 10892 | /* Install more signal handlers */ |
10830 | { | 10893 | install_special_sighandlers(); |
10831 | const char *hp = get_local_var_value("HISTFILE"); | 10894 | # if ENABLE_HUSH_JOB |
10832 | if (!hp) { | 10895 | if (G_saved_tty_pgrp) { |
10833 | hp = get_local_var_value("HOME"); | 10896 | /* Set fatal signals to restore saved_tty_pgrp */ |
10834 | if (hp) { | 10897 | install_fatal_sighandlers(); |
10835 | hp = concat_path_file(hp, ".hush_history"); | 10898 | /* (The if() is an optimization: can avoid two redundant syscalls) */ |
10836 | /* Make HISTFILE set on exit (else history won't be saved) */ | 10899 | if (G_saved_tty_pgrp != G.root_pid) { |
10837 | 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); | ||
10838 | } | 10905 | } |
10839 | } else { | ||
10840 | hp = xstrdup(hp); | ||
10841 | } | 10906 | } |
10842 | if (hp) { | ||
10843 | G.line_input_state->hist_file = hp; | ||
10844 | } | ||
10845 | # if ENABLE_FEATURE_SH_HISTFILESIZE | ||
10846 | hp = get_local_var_value("HISTSIZE"); | ||
10847 | /* Using HISTFILESIZE above to limit max_history would be WRONG: | ||
10848 | * users may set HISTFILESIZE=0 in their profile scripts | ||
10849 | * to prevent _saving_ of history files, but still want to have | ||
10850 | * non-zero history limit for in-memory list. | ||
10851 | */ | ||
10852 | // in bash, runtime history size is controlled by HISTSIZE (0=no history), | ||
10853 | // HISTFILESIZE controls on-disk history file size (in lines, 0=no history): | ||
10854 | G.line_input_state->max_history = size_from_HISTFILESIZE(hp); | ||
10855 | // HISTFILESIZE: "The shell sets the default value to the value of HISTSIZE after reading any startup files." | ||
10856 | // HISTSIZE: "The shell sets the default value to 500 after reading any startup files." | ||
10857 | // (meaning: if the value wasn't set after startup files, the default value is set as described above) | ||
10858 | # endif | ||
10859 | } | ||
10860 | # endif | 10907 | # endif |
10861 | } else { | 10908 | # if ENABLE_FEATURE_EDITING_FANCY_PROMPT |
10862 | install_special_sighandlers(); | 10909 | /* Set (but not export) PS1/2 unless already set */ |
10863 | } | 10910 | if (!get_local_var_value("PS1")) |
10864 | #elif ENABLE_HUSH_INTERACTIVE | 10911 | set_local_var_from_halves("PS1", "\\w \\$ "); |
10865 | /* No job control compiled in, only prompt/line editing */ | 10912 | if (!get_local_var_value("PS2")) |
10866 | if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { | 10913 | set_local_var_from_halves("PS2", "> "); |
10867 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); | 10914 | # endif |
10868 | if (G_interactive_fd < 0) { | 10915 | init_line_editing(); |
10869 | /* try to dup to any fd */ | ||
10870 | G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, -1); | ||
10871 | if (G_interactive_fd < 0) | ||
10872 | /* give up */ | ||
10873 | G_interactive_fd = 0; | ||
10874 | } | ||
10875 | } | ||
10876 | install_special_sighandlers(); | ||
10877 | #else | ||
10878 | /* We have interactiveness code disabled */ | ||
10879 | install_special_sighandlers(); | ||
10880 | #endif | ||
10881 | /* bash: | ||
10882 | * if interactive but not a login shell, sources ~/.bashrc | ||
10883 | * (--norc turns this off, --rcfile <file> overrides) | ||
10884 | */ | ||
10885 | 10916 | ||
10886 | if (G_interactive_fd) { | 10917 | # if !ENABLE_FEATURE_SH_EXTRA_QUIET |
10887 | #if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT | ||
10888 | /* Set (but not export) PS1/2 unless already set */ | ||
10889 | if (!get_local_var_value("PS1")) | ||
10890 | set_local_var_from_halves("PS1", "\\w \\$ "); | ||
10891 | if (!get_local_var_value("PS2")) | ||
10892 | set_local_var_from_halves("PS2", "> "); | ||
10893 | #endif | ||
10894 | if (!ENABLE_FEATURE_SH_EXTRA_QUIET) { | ||
10895 | /* note: ash and hush share this string */ | 10918 | /* note: ash and hush share this string */ |
10896 | printf("\n\n%s %s\n" | 10919 | printf("\n\n%s %s\n" |
10897 | 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") |
@@ -10899,13 +10922,15 @@ int hush_main(int argc, char **argv) | |||
10899 | bb_banner, | 10922 | bb_banner, |
10900 | "hush - the humble shell" | 10923 | "hush - the humble shell" |
10901 | ); | 10924 | ); |
10902 | } | 10925 | # endif |
10903 | } | 10926 | } /* if become interactive */ |
10927 | } /* if on tty */ | ||
10928 | #endif /* if INTERACTIVE is allowed by build config */ | ||
10904 | 10929 | ||
10905 | parse_and_run_file(hfopen(NULL)); /* stdin */ | 10930 | parse_and_run_file(hfopen(NULL)); /* stdin */ |
10906 | 10931 | ||
10907 | final_return: | 10932 | final_return: |
10908 | hush_exit(G.last_exitcode); | 10933 | save_history_run_exit_trap_and_exit(G.last_exitcode); |
10909 | } | 10934 | } |
10910 | 10935 | ||
10911 | /* | 10936 | /* |
@@ -11091,19 +11116,19 @@ static int FAST_FUNC builtin_exit(char **argv) | |||
11091 | * 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" |
11092 | */ | 11117 | */ |
11093 | 11118 | ||
11094 | /* note: EXIT trap is run by hush_exit */ | 11119 | /* note: EXIT trap is run by save_history_run_exit_trap_and_exit */ |
11095 | argv = skip_dash_dash(argv); | 11120 | argv = skip_dash_dash(argv); |
11096 | if (argv[0] == NULL) { | 11121 | if (argv[0] == NULL) { |
11097 | #if ENABLE_HUSH_TRAP | 11122 | #if ENABLE_HUSH_TRAP |
11098 | 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 */ |
11099 | hush_exit(G.pre_trap_exitcode); | 11124 | save_history_run_exit_trap_and_exit(G.pre_trap_exitcode); |
11100 | #endif | 11125 | #endif |
11101 | hush_exit(G.last_exitcode); | 11126 | save_history_run_exit_trap_and_exit(G.last_exitcode); |
11102 | } | 11127 | } |
11103 | /* mimic bash: exit 123abc == exit 255 + error msg */ | 11128 | /* mimic bash: exit 123abc == exit 255 + error msg */ |
11104 | xfunc_error_retval = 255; | 11129 | xfunc_error_retval = 255; |
11105 | /* bash: exit -2 == exit 254, no error msg */ | 11130 | /* bash: exit -2 == exit 254, no error msg */ |
11106 | hush_exit(xatoi(argv[0]) & 0xff); | 11131 | save_history_run_exit_trap_and_exit(xatoi(argv[0]) & 0xff); |
11107 | } | 11132 | } |
11108 | 11133 | ||
11109 | #if ENABLE_HUSH_TYPE | 11134 | #if ENABLE_HUSH_TYPE |
diff --git a/shell/hush_leaktool.sh b/shell/hush_leaktool.sh index ca35ec144..3edd3df61 100755 --- a/shell/hush_leaktool.sh +++ b/shell/hush_leaktool.sh | |||
@@ -7,7 +7,7 @@ freelist=`grep 'free 0x' "$output" | cut -d' ' -f2 | sort | uniq | xargs` | |||
7 | 7 | ||
8 | grep -v free "$output" >"$output.leaked" | 8 | grep -v free "$output" >"$output.leaked" |
9 | 9 | ||
10 | i=8 | 10 | i=16 |
11 | list= | 11 | list= |
12 | for freed in $freelist; do | 12 | for freed in $freelist; do |
13 | list="$list -e $freed" | 13 | list="$list -e $freed" |
@@ -15,7 +15,7 @@ for freed in $freelist; do | |||
15 | echo Dropping $list | 15 | echo Dropping $list |
16 | grep -F -v $list <"$output.leaked" >"$output.temp" | 16 | grep -F -v $list <"$output.leaked" >"$output.temp" |
17 | mv "$output.temp" "$output.leaked" | 17 | mv "$output.temp" "$output.leaked" |
18 | i=8 | 18 | i=16 |
19 | list= | 19 | list= |
20 | done | 20 | done |
21 | if test "$list"; then | 21 | if test "$list"; then |
@@ -23,3 +23,17 @@ if test "$list"; then | |||
23 | grep -F -v $list <"$output.leaked" >"$output.temp" | 23 | grep -F -v $list <"$output.leaked" >"$output.temp" |
24 | mv "$output.temp" "$output.leaked" | 24 | mv "$output.temp" "$output.leaked" |
25 | fi | 25 | fi |
26 | |||
27 | # All remaining allocations are on addresses which were never freed. | ||
28 | # * Sort them by line, grouping together allocations which allocated the same address. | ||
29 | # A leaky allocation will give many different addresses (because it's never freed, | ||
30 | # the address can not be reused). | ||
31 | # * Remove the address (field #4). | ||
32 | # * Count the allocations per every unique source line and alloc type. | ||
33 | # * Show largest counts on top. | ||
34 | cat output.leaked \ | ||
35 | | sort -u \ | ||
36 | | cut -d' ' -f1-3 \ | ||
37 | | uniq -c \ | ||
38 | | sort -rn \ | ||
39 | >output.leaked.counted_uniq_alloc_address | ||
diff --git a/shell/hush_test/hush-misc/sig_exitcode.tests b/shell/hush_test/hush-misc/sig_exitcode.tests index 7879dc854..67b4500f4 100755 --- a/shell/hush_test/hush-misc/sig_exitcode.tests +++ b/shell/hush_test/hush-misc/sig_exitcode.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | exec 2>&1 | 4 | exec 2>&1 |
2 | 5 | ||
3 | $THIS_SH -c 'kill -9 $$' | 6 | $THIS_SH -c 'kill -9 $$' |
diff --git a/shell/hush_test/hush-misc/wait1.tests b/shell/hush_test/hush-misc/wait1.tests index f9cf6d48c..54120319b 100755 --- a/shell/hush_test/hush-misc/wait1.tests +++ b/shell/hush_test/hush-misc/wait1.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | sleep 2 & sleep 1 & wait $! | 4 | sleep 2 & sleep 1 & wait $! |
2 | echo $? | 5 | echo $? |
3 | jobs | 6 | jobs |
diff --git a/shell/hush_test/hush-misc/wait2.tests b/shell/hush_test/hush-misc/wait2.tests index be20f95a5..60f382c9f 100755 --- a/shell/hush_test/hush-misc/wait2.tests +++ b/shell/hush_test/hush-misc/wait2.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | sleep 3 & sleep 2 & sleep 1 | 4 | sleep 3 & sleep 2 & sleep 1 |
2 | wait $! | 5 | wait $! |
3 | echo $? | 6 | echo $? |
diff --git a/shell/hush_test/hush-misc/wait3.tests b/shell/hush_test/hush-misc/wait3.tests index ac541c3fc..aceed1126 100755 --- a/shell/hush_test/hush-misc/wait3.tests +++ b/shell/hush_test/hush-misc/wait3.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | sleep 2 & (sleep 1;exit 3) & wait $! | 4 | sleep 2 & (sleep 1;exit 3) & wait $! |
2 | echo $? | 5 | echo $? |
3 | jobs | 6 | jobs |
diff --git a/shell/hush_test/hush-misc/wait4.tests b/shell/hush_test/hush-misc/wait4.tests index cc34059ac..c979a38b6 100755 --- a/shell/hush_test/hush-misc/wait4.tests +++ b/shell/hush_test/hush-misc/wait4.tests | |||
@@ -1,2 +1,5 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | sleep 1 | (sleep 1;exit 3) & wait %1 | 4 | sleep 1 | (sleep 1;exit 3) & wait %1 |
2 | echo Three:$? | 5 | echo Three:$? |
diff --git a/shell/hush_test/hush-misc/wait5.tests b/shell/hush_test/hush-misc/wait5.tests index 1b4762d89..e0ac8c251 100755 --- a/shell/hush_test/hush-misc/wait5.tests +++ b/shell/hush_test/hush-misc/wait5.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | sleep 0 | (sleep 0;exit 3) & | 4 | sleep 0 | (sleep 0;exit 3) & |
2 | sleep 1 | 5 | sleep 1 |
3 | echo Zero:$? | 6 | echo Zero:$? |
diff --git a/shell/hush_test/hush-misc/wait6.tests b/shell/hush_test/hush-misc/wait6.tests index c23713199..c09002ab0 100755 --- a/shell/hush_test/hush-misc/wait6.tests +++ b/shell/hush_test/hush-misc/wait6.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | # In bash, "wait $!" extracts correct exitcode even if bg task has already exited | 4 | # In bash, "wait $!" extracts correct exitcode even if bg task has already exited |
2 | # It prints 0, then 3: | 5 | # It prints 0, then 3: |
3 | (sleep 0; exit 3) & sleep 1 | 6 | (sleep 0; exit 3) & sleep 1 |
diff --git a/shell/hush_test/hush-signals/catch.tests b/shell/hush_test/hush-signals/catch.tests index d2a21d17e..4b1a08e8f 100755 --- a/shell/hush_test/hush-signals/catch.tests +++ b/shell/hush_test/hush-signals/catch.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test ("User defined signal 2" text not emitted) | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | # avoid ugly warnings about signals not being caught | 4 | # avoid ugly warnings about signals not being caught |
2 | trap ":" USR1 USR2 | 5 | trap ":" USR1 USR2 |
3 | 6 | ||
diff --git a/shell/hush_test/hush-signals/signal1.tests b/shell/hush_test/hush-signals/signal1.tests index 61943467a..c83fa1254 100755 --- a/shell/hush_test/hush-signals/signal1.tests +++ b/shell/hush_test/hush-signals/signal1.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | trap "echo got signal" USR1 | 4 | trap "echo got signal" USR1 |
2 | 5 | ||
3 | for try in 1 2 3 4 5; do | 6 | for try in 1 2 3 4 5; do |
diff --git a/shell/hush_test/hush-signals/signal8.tests b/shell/hush_test/hush-signals/signal8.tests index 731af7477..cd5790164 100755 --- a/shell/hush_test/hush-signals/signal8.tests +++ b/shell/hush_test/hush-signals/signal8.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | "$THIS_SH" -c ' | 4 | "$THIS_SH" -c ' |
2 | exit_func() { | 5 | exit_func() { |
3 | echo "Removing traps" | 6 | echo "Removing traps" |
diff --git a/shell/hush_test/hush-signals/signal_read2.tests b/shell/hush_test/hush-signals/signal_read2.tests index eab5b9b5b..11accd5ab 100755 --- a/shell/hush_test/hush-signals/signal_read2.tests +++ b/shell/hush_test/hush-signals/signal_read2.tests | |||
@@ -1,3 +1,6 @@ | |||
1 | # If job control is disabled, skip the test ("Hangup" not emitted) | ||
2 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
3 | |||
1 | $THIS_SH -c ' | 4 | $THIS_SH -c ' |
2 | (sleep 1; kill -HUP $$) & | 5 | (sleep 1; kill -HUP $$) & |
3 | while true; do | 6 | while true; do |
diff --git a/shell/hush_test/hush-signals/subshell.tests b/shell/hush_test/hush-signals/subshell.tests index d877f2b82..856c922d3 100755 --- a/shell/hush_test/hush-signals/subshell.tests +++ b/shell/hush_test/hush-signals/subshell.tests | |||
@@ -1,5 +1,8 @@ | |||
1 | # Non-empty traps should be reset in subshell | 1 | # Non-empty traps should be reset in subshell |
2 | 2 | ||
3 | # If job control is disabled, skip the test ("Terminated" text not emitted) | ||
4 | test "`type jobs`" = "jobs is a shell builtin" || exit 77 | ||
5 | |||
3 | # HUP is special in interactive shells | 6 | # HUP is special in interactive shells |
4 | trap '' HUP | 7 | trap '' HUP |
5 | # QUIT is always special | 8 | # QUIT is always special |
diff --git a/shell/hush_test/run-all b/shell/hush_test/run-all index 7345fee43..ff29ca0b1 100755 --- a/shell/hush_test/run-all +++ b/shell/hush_test/run-all | |||
@@ -67,9 +67,12 @@ do_test() | |||
67 | # echo Running test: "$x" | 67 | # echo Running test: "$x" |
68 | echo -n "$1/$x:" | 68 | echo -n "$1/$x:" |
69 | ( | 69 | ( |
70 | "$THIS_SH" "./$x" 2>&1 | \ | 70 | "$THIS_SH" "./$x" >"$name.xx" 2>&1 |
71 | grep -va "^hush: using fallback suid method$" >"$name.xx" | ||
72 | r=$? | 71 | r=$? |
72 | # filter !FEATURE_SUID_CONFIG_QUIET message | ||
73 | sed -i \ | ||
74 | -e "/^hush: using fallback suid method$/d" \ | ||
75 | "$name.xx" | ||
73 | # filter C library differences | 76 | # filter C library differences |
74 | sed -i \ | 77 | sed -i \ |
75 | -e "/: invalid option /s:'::g" \ | 78 | -e "/: invalid option /s:'::g" \ |