diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 152 |
1 files changed, 110 insertions, 42 deletions
diff --git a/shell/ash.c b/shell/ash.c index 6a572cbc3..ac1ae05fc 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -215,6 +215,9 @@ | |||
215 | #define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT | 215 | #define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT |
216 | #define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT | 216 | #define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT |
217 | #define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT | 217 | #define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT |
218 | #define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT | ||
219 | #define BASH_READ_D ENABLE_ASH_BASH_COMPAT | ||
220 | #define IF_BASH_READ_D IF_ASH_BASH_COMPAT | ||
218 | 221 | ||
219 | #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 | 222 | #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 |
220 | /* Bionic at least up to version 24 has no glob() */ | 223 | /* Bionic at least up to version 24 has no glob() */ |
@@ -452,7 +455,7 @@ struct globals_misc { | |||
452 | #define S_DFL 1 /* default signal handling (SIG_DFL) */ | 455 | #define S_DFL 1 /* default signal handling (SIG_DFL) */ |
453 | #define S_CATCH 2 /* signal is caught */ | 456 | #define S_CATCH 2 /* signal is caught */ |
454 | #define S_IGN 3 /* signal is ignored (SIG_IGN) */ | 457 | #define S_IGN 3 /* signal is ignored (SIG_IGN) */ |
455 | #define S_HARD_IGN 4 /* signal is ignored permanently */ | 458 | #define S_HARD_IGN 4 /* signal is ignored permanently (it was SIG_IGN on entry to shell) */ |
456 | 459 | ||
457 | /* indicates specified signal received */ | 460 | /* indicates specified signal received */ |
458 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ | 461 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ |
@@ -1313,6 +1316,10 @@ struct strpush { | |||
1313 | int unget; | 1316 | int unget; |
1314 | }; | 1317 | }; |
1315 | 1318 | ||
1319 | /* | ||
1320 | * The parsefile structure pointed to by the global variable parsefile | ||
1321 | * contains information about the current file being read. | ||
1322 | */ | ||
1316 | struct parsefile { | 1323 | struct parsefile { |
1317 | struct parsefile *prev; /* preceding file on stack */ | 1324 | struct parsefile *prev; /* preceding file on stack */ |
1318 | int linno; /* current line */ | 1325 | int linno; /* current line */ |
@@ -1986,10 +1993,6 @@ nextopt(const char *optstring) | |||
1986 | 1993 | ||
1987 | /* ============ Shell variables */ | 1994 | /* ============ Shell variables */ |
1988 | 1995 | ||
1989 | /* | ||
1990 | * The parsefile structure pointed to by the global variable parsefile | ||
1991 | * contains information about the current file being read. | ||
1992 | */ | ||
1993 | struct shparam { | 1996 | struct shparam { |
1994 | int nparam; /* # of positional parameters (without $0) */ | 1997 | int nparam; /* # of positional parameters (without $0) */ |
1995 | #if ENABLE_ASH_GETOPTS | 1998 | #if ENABLE_ASH_GETOPTS |
@@ -2183,7 +2186,9 @@ extern struct globals_var *const ash_ptr_to_globals_var; | |||
2183 | static void FAST_FUNC | 2186 | static void FAST_FUNC |
2184 | getoptsreset(const char *value) | 2187 | getoptsreset(const char *value) |
2185 | { | 2188 | { |
2186 | shellparam.optind = number(value) ?: 1; | 2189 | shellparam.optind = 1; |
2190 | if (is_number(value)) | ||
2191 | shellparam.optind = number(value) ?: 1; | ||
2187 | shellparam.optoff = -1; | 2192 | shellparam.optoff = -1; |
2188 | } | 2193 | } |
2189 | #endif | 2194 | #endif |
@@ -3751,9 +3756,12 @@ setsignal(int signo) | |||
3751 | #endif | 3756 | #endif |
3752 | } | 3757 | } |
3753 | } | 3758 | } |
3754 | //TODO: if !rootshell, we reset SIGQUIT to DFL, | 3759 | /* if !rootshell, we reset SIGQUIT to DFL, |
3755 | //whereas we have to restore it to what shell got on entry | 3760 | * whereas we have to restore it to what shell got on entry. |
3756 | //from the parent. See comment above | 3761 | * This is handled by the fact that if signal was IGNored on entry, |
3762 | * then cur_act is S_HARD_IGN and we never change its sigaction | ||
3763 | * (see code below). | ||
3764 | */ | ||
3757 | 3765 | ||
3758 | if (signo == SIGCHLD) | 3766 | if (signo == SIGCHLD) |
3759 | new_act = S_CATCH; | 3767 | new_act = S_CATCH; |
@@ -3777,10 +3785,18 @@ setsignal(int signo) | |||
3777 | cur_act = S_IGN; /* don't hard ignore these */ | 3785 | cur_act = S_IGN; /* don't hard ignore these */ |
3778 | } | 3786 | } |
3779 | } | 3787 | } |
3788 | if (act.sa_handler == SIG_DFL && new_act == S_DFL) { | ||
3789 | /* installing SIG_DFL over SIG_DFL is a no-op */ | ||
3790 | /* saves one sigaction call in each "sh -c SCRIPT" invocation */ | ||
3791 | *t = S_DFL; | ||
3792 | return; | ||
3793 | } | ||
3780 | } | 3794 | } |
3781 | if (cur_act == S_HARD_IGN || cur_act == new_act) | 3795 | if (cur_act == S_HARD_IGN || cur_act == new_act) |
3782 | return; | 3796 | return; |
3783 | 3797 | ||
3798 | *t = new_act; | ||
3799 | |||
3784 | act.sa_handler = SIG_DFL; | 3800 | act.sa_handler = SIG_DFL; |
3785 | switch (new_act) { | 3801 | switch (new_act) { |
3786 | case S_CATCH: | 3802 | case S_CATCH: |
@@ -3790,16 +3806,13 @@ setsignal(int signo) | |||
3790 | act.sa_handler = SIG_IGN; | 3806 | act.sa_handler = SIG_IGN; |
3791 | break; | 3807 | break; |
3792 | } | 3808 | } |
3793 | |||
3794 | /* flags and mask matter only if !DFL and !IGN, but we do it | 3809 | /* flags and mask matter only if !DFL and !IGN, but we do it |
3795 | * for all cases for more deterministic behavior: | 3810 | * for all cases for more deterministic behavior: |
3796 | */ | 3811 | */ |
3797 | act.sa_flags = 0; | 3812 | act.sa_flags = 0; //TODO: why not SA_RESTART? |
3798 | sigfillset(&act.sa_mask); | 3813 | sigfillset(&act.sa_mask); |
3799 | 3814 | ||
3800 | sigaction_set(signo, &act); | 3815 | sigaction_set(signo, &act); |
3801 | |||
3802 | *t = new_act; | ||
3803 | } | 3816 | } |
3804 | #else | 3817 | #else |
3805 | #define setsignal(s) | 3818 | #define setsignal(s) |
@@ -5915,12 +5928,10 @@ static void | |||
5915 | redirect(union node *redir, int flags) | 5928 | redirect(union node *redir, int flags) |
5916 | { | 5929 | { |
5917 | struct redirtab *sv; | 5930 | struct redirtab *sv; |
5918 | int sv_pos; | ||
5919 | 5931 | ||
5920 | if (!redir) | 5932 | if (!redir) |
5921 | return; | 5933 | return; |
5922 | 5934 | ||
5923 | sv_pos = 0; | ||
5924 | sv = NULL; | 5935 | sv = NULL; |
5925 | INT_OFF; | 5936 | INT_OFF; |
5926 | if (flags & REDIR_PUSH) | 5937 | if (flags & REDIR_PUSH) |
@@ -8076,8 +8087,9 @@ static int | |||
8076 | patmatch(char *pattern, const char *string) | 8087 | patmatch(char *pattern, const char *string) |
8077 | { | 8088 | { |
8078 | char *p = preglob(pattern, 0); | 8089 | char *p = preglob(pattern, 0); |
8079 | //bb_error_msg("fnmatch(pattern:'%s',str:'%s')", p, string); | 8090 | int r = pmatch(p, string); |
8080 | return pmatch(p, string); | 8091 | //bb_error_msg("!fnmatch(pattern:'%s',str:'%s',0):%d", p, string, r); |
8092 | return r; | ||
8081 | } | 8093 | } |
8082 | 8094 | ||
8083 | /* | 8095 | /* |
@@ -8179,7 +8191,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
8179 | while (*envp) | 8191 | while (*envp) |
8180 | putenv(*envp++); | 8192 | putenv(*envp++); |
8181 | popredir(/*drop:*/ 1); | 8193 | popredir(/*drop:*/ 1); |
8182 | run_applet_no_and_exit(applet_no, cmd, argv); | 8194 | run_noexec_applet_and_exit(applet_no, cmd, argv); |
8183 | } | 8195 | } |
8184 | /* re-exec ourselves with the new arguments */ | 8196 | /* re-exec ourselves with the new arguments */ |
8185 | execve(bb_busybox_exec_path, argv, envp); | 8197 | execve(bb_busybox_exec_path, argv, envp); |
@@ -10250,6 +10262,15 @@ evalcommand(union node *cmd, int flags) | |||
10250 | expredir(cmd->ncmd.redirect); | 10262 | expredir(cmd->ncmd.redirect); |
10251 | redir_stop = pushredir(cmd->ncmd.redirect); | 10263 | redir_stop = pushredir(cmd->ncmd.redirect); |
10252 | preverrout_fd = 2; | 10264 | preverrout_fd = 2; |
10265 | if (BASH_XTRACEFD && xflag) { | ||
10266 | /* NB: bash closes fd == $BASH_XTRACEFD when it is changed. | ||
10267 | * we do not emulate this. We only use its value. | ||
10268 | */ | ||
10269 | const char *xtracefd = lookupvar("BASH_XTRACEFD"); | ||
10270 | if (xtracefd && is_number(xtracefd)) | ||
10271 | preverrout_fd = atoi(xtracefd); | ||
10272 | |||
10273 | } | ||
10253 | status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); | 10274 | status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); |
10254 | 10275 | ||
10255 | path = vpath.var_text; | 10276 | path = vpath.var_text; |
@@ -10383,12 +10404,30 @@ evalcommand(union node *cmd, int flags) | |||
10383 | #endif | 10404 | #endif |
10384 | ) { | 10405 | ) { |
10385 | listsetvar(varlist.list, VEXPORT|VSTACK); | 10406 | listsetvar(varlist.list, VEXPORT|VSTACK); |
10386 | /* run <applet>_main() */ | 10407 | /* |
10408 | * Run <applet>_main(). | ||
10409 | * Signals (^C) can't interrupt here. | ||
10410 | * Otherwise we can mangle stdio or malloc internal state. | ||
10411 | * This makes applets which can run for a long time | ||
10412 | * and/or wait for user input ineligible for NOFORK: | ||
10413 | * for example, "yes" or "rm" (rm -i waits for input). | ||
10414 | */ | ||
10415 | INT_OFF; | ||
10387 | status = run_nofork_applet(applet_no, argv); | 10416 | status = run_nofork_applet(applet_no, argv); |
10417 | /* | ||
10418 | * Try enabling NOFORK for "yes" applet. | ||
10419 | * ^C _will_ stop it (write returns EINTR), | ||
10420 | * but this causes stdout FILE to be stuck | ||
10421 | * and needing clearerr(). What if other applets | ||
10422 | * also can get EINTRs? Do we need to switch | ||
10423 | * our signals to SA_RESTART? | ||
10424 | */ | ||
10425 | /*clearerr(stdout);*/ | ||
10426 | INT_ON; | ||
10388 | break; | 10427 | break; |
10389 | } | 10428 | } |
10390 | #endif | 10429 | #endif |
10391 | /* Can we avoid forking off? For example, very last command | 10430 | /* Can we avoid forking? For example, very last command |
10392 | * in a script or a subshell does not need forking, | 10431 | * in a script or a subshell does not need forking, |
10393 | * we can just exec it. | 10432 | * we can just exec it. |
10394 | */ | 10433 | */ |
@@ -10674,8 +10713,8 @@ preadfd(void) | |||
10674 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) | 10713 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) |
10675 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); | 10714 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
10676 | else { | 10715 | else { |
10677 | int timeout = -1; | ||
10678 | # if ENABLE_ASH_IDLE_TIMEOUT | 10716 | # if ENABLE_ASH_IDLE_TIMEOUT |
10717 | int timeout = -1; | ||
10679 | if (iflag) { | 10718 | if (iflag) { |
10680 | const char *tmout_var = lookupvar("TMOUT"); | 10719 | const char *tmout_var = lookupvar("TMOUT"); |
10681 | if (tmout_var) { | 10720 | if (tmout_var) { |
@@ -10684,12 +10723,13 @@ preadfd(void) | |||
10684 | timeout = -1; | 10723 | timeout = -1; |
10685 | } | 10724 | } |
10686 | } | 10725 | } |
10726 | line_input_state->timeout = timeout; | ||
10687 | # endif | 10727 | # endif |
10688 | # if ENABLE_FEATURE_TAB_COMPLETION | 10728 | # if ENABLE_FEATURE_TAB_COMPLETION |
10689 | line_input_state->path_lookup = pathval(); | 10729 | line_input_state->path_lookup = pathval(); |
10690 | # endif | 10730 | # endif |
10691 | reinit_unicode_for_ash(); | 10731 | reinit_unicode_for_ash(); |
10692 | nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); | 10732 | nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ); |
10693 | if (nr == 0) { | 10733 | if (nr == 0) { |
10694 | /* ^C pressed, "convert" to SIGINT */ | 10734 | /* ^C pressed, "convert" to SIGINT */ |
10695 | write(STDOUT_FILENO, "^C", 2); | 10735 | write(STDOUT_FILENO, "^C", 2); |
@@ -11399,6 +11439,7 @@ getopts(char *optstr, char *optvar, char **optfirst) | |||
11399 | p = *optnext; | 11439 | p = *optnext; |
11400 | if (p == NULL || *p != '-' || *++p == '\0') { | 11440 | if (p == NULL || *p != '-' || *++p == '\0') { |
11401 | atend: | 11441 | atend: |
11442 | unsetvar("OPTARG"); | ||
11402 | p = NULL; | 11443 | p = NULL; |
11403 | done = 1; | 11444 | done = 1; |
11404 | goto out; | 11445 | goto out; |
@@ -11411,7 +11452,11 @@ getopts(char *optstr, char *optvar, char **optfirst) | |||
11411 | c = *p++; | 11452 | c = *p++; |
11412 | for (q = optstr; *q != c;) { | 11453 | for (q = optstr; *q != c;) { |
11413 | if (*q == '\0') { | 11454 | if (*q == '\0') { |
11414 | if (optstr[0] == ':') { | 11455 | /* OPTERR is a bashism */ |
11456 | const char *cp = lookupvar("OPTERR"); | ||
11457 | if ((cp && LONE_CHAR(cp, '0')) | ||
11458 | || (optstr[0] == ':') | ||
11459 | ) { | ||
11415 | sbuf[0] = c; | 11460 | sbuf[0] = c; |
11416 | /*sbuf[1] = '\0'; - already is */ | 11461 | /*sbuf[1] = '\0'; - already is */ |
11417 | setvar0("OPTARG", sbuf); | 11462 | setvar0("OPTARG", sbuf); |
@@ -11428,7 +11473,11 @@ getopts(char *optstr, char *optvar, char **optfirst) | |||
11428 | 11473 | ||
11429 | if (*++q == ':') { | 11474 | if (*++q == ':') { |
11430 | if (*p == '\0' && (p = *optnext) == NULL) { | 11475 | if (*p == '\0' && (p = *optnext) == NULL) { |
11431 | if (optstr[0] == ':') { | 11476 | /* OPTERR is a bashism */ |
11477 | const char *cp = lookupvar("OPTERR"); | ||
11478 | if ((cp && LONE_CHAR(cp, '0')) | ||
11479 | || (optstr[0] == ':') | ||
11480 | ) { | ||
11432 | sbuf[0] = c; | 11481 | sbuf[0] = c; |
11433 | /*sbuf[1] = '\0'; - already is */ | 11482 | /*sbuf[1] = '\0'; - already is */ |
11434 | setvar0("OPTARG", sbuf); | 11483 | setvar0("OPTARG", sbuf); |
@@ -12571,7 +12620,7 @@ parsesub: { | |||
12571 | STPUTC(c, out); | 12620 | STPUTC(c, out); |
12572 | c = pgetc_eatbnl(); | 12621 | c = pgetc_eatbnl(); |
12573 | } while (isdigit(c)); | 12622 | } while (isdigit(c)); |
12574 | } else if (is_special(c)) { | 12623 | } else { |
12575 | /* $[{[#]]<specialchar>[}] */ | 12624 | /* $[{[#]]<specialchar>[}] */ |
12576 | int cc = c; | 12625 | int cc = c; |
12577 | 12626 | ||
@@ -12589,10 +12638,16 @@ parsesub: { | |||
12589 | cc = '#'; | 12638 | cc = '#'; |
12590 | } | 12639 | } |
12591 | } | 12640 | } |
12641 | |||
12642 | if (!is_special(cc)) { | ||
12643 | if (subtype == VSLENGTH) | ||
12644 | subtype = 0; | ||
12645 | goto badsub; | ||
12646 | } | ||
12647 | |||
12592 | USTPUTC(cc, out); | 12648 | USTPUTC(cc, out); |
12593 | } else { | ||
12594 | goto badsub; | ||
12595 | } | 12649 | } |
12650 | |||
12596 | if (c != '}' && subtype == VSLENGTH) { | 12651 | if (c != '}' && subtype == VSLENGTH) { |
12597 | /* ${#VAR didn't end with } */ | 12652 | /* ${#VAR didn't end with } */ |
12598 | goto badsub; | 12653 | goto badsub; |
@@ -13850,21 +13905,23 @@ static const unsigned char timescmd_str[] ALIGN1 = { | |||
13850 | static int FAST_FUNC | 13905 | static int FAST_FUNC |
13851 | timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 13906 | timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) |
13852 | { | 13907 | { |
13853 | unsigned long clk_tck, s, t; | 13908 | unsigned clk_tck; |
13854 | const unsigned char *p; | 13909 | const unsigned char *p; |
13855 | struct tms buf; | 13910 | struct tms buf; |
13856 | 13911 | ||
13857 | clk_tck = bb_clk_tck(); | 13912 | clk_tck = bb_clk_tck(); |
13858 | times(&buf); | ||
13859 | 13913 | ||
13914 | times(&buf); | ||
13860 | p = timescmd_str; | 13915 | p = timescmd_str; |
13861 | do { | 13916 | do { |
13917 | unsigned sec, frac; | ||
13918 | unsigned long t; | ||
13862 | t = *(clock_t *)(((char *) &buf) + p[1]); | 13919 | t = *(clock_t *)(((char *) &buf) + p[1]); |
13863 | s = t / clk_tck; | 13920 | sec = t / clk_tck; |
13864 | t = t % clk_tck; | 13921 | frac = t % clk_tck; |
13865 | out1fmt("%lum%lu.%03lus%c", | 13922 | out1fmt("%um%u.%03us%c", |
13866 | s / 60, s % 60, | 13923 | sec / 60, sec % 60, |
13867 | (t * 1000) / clk_tck, | 13924 | (frac * 1000) / clk_tck, |
13868 | p[0]); | 13925 | p[0]); |
13869 | p += 2; | 13926 | p += 2; |
13870 | } while (*p); | 13927 | } while (*p); |
@@ -13903,10 +13960,10 @@ letcmd(int argc UNUSED_PARAM, char **argv) | |||
13903 | * -p PROMPT Display PROMPT on stderr (if input is from tty) | 13960 | * -p PROMPT Display PROMPT on stderr (if input is from tty) |
13904 | * -t SECONDS Timeout after SECONDS (tty or pipe only) | 13961 | * -t SECONDS Timeout after SECONDS (tty or pipe only) |
13905 | * -u FD Read from given FD instead of fd 0 | 13962 | * -u FD Read from given FD instead of fd 0 |
13963 | * -d DELIM End on DELIM char, not newline | ||
13906 | * This uses unbuffered input, which may be avoidable in some cases. | 13964 | * This uses unbuffered input, which may be avoidable in some cases. |
13907 | * TODO: bash also has: | 13965 | * TODO: bash also has: |
13908 | * -a ARRAY Read into array[0],[1],etc | 13966 | * -a ARRAY Read into array[0],[1],etc |
13909 | * -d DELIM End on DELIM char, not newline | ||
13910 | * -e Use line editing (tty only) | 13967 | * -e Use line editing (tty only) |
13911 | */ | 13968 | */ |
13912 | static int FAST_FUNC | 13969 | static int FAST_FUNC |
@@ -13916,11 +13973,12 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
13916 | char *opt_p = NULL; | 13973 | char *opt_p = NULL; |
13917 | char *opt_t = NULL; | 13974 | char *opt_t = NULL; |
13918 | char *opt_u = NULL; | 13975 | char *opt_u = NULL; |
13976 | char *opt_d = NULL; /* optimized out if !BASH */ | ||
13919 | int read_flags = 0; | 13977 | int read_flags = 0; |
13920 | const char *r; | 13978 | const char *r; |
13921 | int i; | 13979 | int i; |
13922 | 13980 | ||
13923 | while ((i = nextopt("p:u:rt:n:s")) != '\0') { | 13981 | while ((i = nextopt("p:u:rt:n:sd:")) != '\0') { |
13924 | switch (i) { | 13982 | switch (i) { |
13925 | case 'p': | 13983 | case 'p': |
13926 | opt_p = optionarg; | 13984 | opt_p = optionarg; |
@@ -13940,6 +13998,11 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
13940 | case 'u': | 13998 | case 'u': |
13941 | opt_u = optionarg; | 13999 | opt_u = optionarg; |
13942 | break; | 14000 | break; |
14001 | #if BASH_READ_D | ||
14002 | case 'd': | ||
14003 | opt_d = optionarg; | ||
14004 | break; | ||
14005 | #endif | ||
13943 | default: | 14006 | default: |
13944 | break; | 14007 | break; |
13945 | } | 14008 | } |
@@ -13957,12 +14020,15 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
13957 | opt_n, | 14020 | opt_n, |
13958 | opt_p, | 14021 | opt_p, |
13959 | opt_t, | 14022 | opt_t, |
13960 | opt_u | 14023 | opt_u, |
14024 | opt_d | ||
13961 | ); | 14025 | ); |
13962 | INT_ON; | 14026 | INT_ON; |
13963 | 14027 | ||
13964 | if ((uintptr_t)r == 1 && errno == EINTR) { | 14028 | if ((uintptr_t)r == 1 && errno == EINTR) { |
13965 | /* to get SIGCHLD: sleep 1 & read x; echo $x */ | 14029 | /* To get SIGCHLD: sleep 1 & read x; echo $x |
14030 | * Correct behavior is to not exit "read" | ||
14031 | */ | ||
13966 | if (pending_sig == 0) | 14032 | if (pending_sig == 0) |
13967 | goto again; | 14033 | goto again; |
13968 | } | 14034 | } |
@@ -14077,7 +14143,8 @@ exitshell(void) | |||
14077 | /* NOTREACHED */ | 14143 | /* NOTREACHED */ |
14078 | } | 14144 | } |
14079 | 14145 | ||
14080 | static void | 14146 | /* Don't inline: conserve stack of caller from having our locals too */ |
14147 | static NOINLINE void | ||
14081 | #if ENABLE_PLATFORM_MINGW32 | 14148 | #if ENABLE_PLATFORM_MINGW32 |
14082 | init(int xp) | 14149 | init(int xp) |
14083 | #else | 14150 | #else |
@@ -14086,8 +14153,9 @@ init(void) | |||
14086 | { | 14153 | { |
14087 | /* we will never free this */ | 14154 | /* we will never free this */ |
14088 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); | 14155 | basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); |
14156 | basepf.linno = 1; | ||
14089 | 14157 | ||
14090 | sigmode[SIGCHLD - 1] = S_DFL; | 14158 | sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */ |
14091 | setsignal(SIGCHLD); | 14159 | setsignal(SIGCHLD); |
14092 | 14160 | ||
14093 | /* bash re-enables SIGHUP which is SIG_IGNed on entry. | 14161 | /* bash re-enables SIGHUP which is SIG_IGNed on entry. |
@@ -14098,7 +14166,6 @@ init(void) | |||
14098 | { | 14166 | { |
14099 | char **envp; | 14167 | char **envp; |
14100 | const char *p; | 14168 | const char *p; |
14101 | struct stat st1, st2; | ||
14102 | 14169 | ||
14103 | initvar(); | 14170 | initvar(); |
14104 | 14171 | ||
@@ -14204,6 +14271,7 @@ init(void) | |||
14204 | #endif | 14271 | #endif |
14205 | p = lookupvar("PWD"); | 14272 | p = lookupvar("PWD"); |
14206 | if (p) { | 14273 | if (p) { |
14274 | struct stat st1, st2; | ||
14207 | if (p[0] != '/' || stat(p, &st1) || stat(".", &st2) | 14275 | if (p[0] != '/' || stat(p, &st1) || stat(".", &st2) |
14208 | || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino | 14276 | || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino |
14209 | ) { | 14277 | ) { |
@@ -15161,7 +15229,7 @@ sticky_free(void *base) | |||
15161 | * may be used to endorse or promote products derived from this software | 15229 | * may be used to endorse or promote products derived from this software |
15162 | * without specific prior written permission. | 15230 | * without specific prior written permission. |
15163 | * | 15231 | * |
15164 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 15232 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND |
15165 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 15233 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15166 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 15234 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
15167 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 15235 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |