diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 193 |
1 files changed, 128 insertions, 65 deletions
diff --git a/shell/ash.c b/shell/ash.c index b82c51029..690485a83 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -416,10 +416,18 @@ static const char *const optletters_optnames[] = { | |||
416 | "e" "errexit", | 416 | "e" "errexit", |
417 | "f" "noglob", | 417 | "f" "noglob", |
418 | "I" "ignoreeof", | 418 | "I" "ignoreeof", |
419 | "i" "interactive", | 419 | /* The below allowed this invocation: |
420 | * ash -c 'set -i; echo $-; sleep 5; echo $-' | ||
421 | * to be ^C-ed and get to interactive ash prompt. | ||
422 | * bash does not support such "set -i". | ||
423 | * In our code, this is denoted by empty long name: | ||
424 | */ | ||
425 | "i" "", | ||
420 | "m" "monitor", | 426 | "m" "monitor", |
421 | "n" "noexec", | 427 | "n" "noexec", |
422 | "s" "stdin", | 428 | /* Ditto: bash has no "set -s" */ |
429 | "s" "", | ||
430 | "c" "", | ||
423 | "x" "xtrace", | 431 | "x" "xtrace", |
424 | "v" "verbose", | 432 | "v" "verbose", |
425 | "C" "noclobber", | 433 | "C" "noclobber", |
@@ -444,6 +452,20 @@ static const char *const optletters_optnames[] = { | |||
444 | ,"\0" "nocaseglob" | 452 | ,"\0" "nocaseglob" |
445 | #endif | 453 | #endif |
446 | }; | 454 | }; |
455 | //bash 4.4.23 also has these opts (with these defaults): | ||
456 | //braceexpand on | ||
457 | //emacs on | ||
458 | //errtrace off | ||
459 | //functrace off | ||
460 | //hashall on | ||
461 | //histexpand off | ||
462 | //history on | ||
463 | //interactive-comments on | ||
464 | //keyword off | ||
465 | //onecmd off | ||
466 | //physical off | ||
467 | //posix off | ||
468 | //privileged off | ||
447 | 469 | ||
448 | #define optletters(n) optletters_optnames[n][0] | 470 | #define optletters(n) optletters_optnames[n][0] |
449 | #define optnames(n) (optletters_optnames[n] + 1) | 471 | #define optnames(n) (optletters_optnames[n] + 1) |
@@ -517,21 +539,22 @@ struct globals_misc { | |||
517 | #define mflag optlist[4] | 539 | #define mflag optlist[4] |
518 | #define nflag optlist[5] | 540 | #define nflag optlist[5] |
519 | #define sflag optlist[6] | 541 | #define sflag optlist[6] |
520 | #define xflag optlist[7] | 542 | #define cflag optlist[7] |
521 | #define vflag optlist[8] | 543 | #define xflag optlist[8] |
522 | #define Cflag optlist[9] | 544 | #define vflag optlist[9] |
523 | #define aflag optlist[10] | 545 | #define Cflag optlist[10] |
524 | #define bflag optlist[11] | 546 | #define aflag optlist[11] |
525 | #define uflag optlist[12] | 547 | #define bflag optlist[12] |
526 | #define viflag optlist[13] | 548 | #define uflag optlist[13] |
549 | #define viflag optlist[14] | ||
527 | #if BASH_PIPEFAIL | 550 | #if BASH_PIPEFAIL |
528 | # define pipefail optlist[14] | 551 | # define pipefail optlist[15] |
529 | #else | 552 | #else |
530 | # define pipefail 0 | 553 | # define pipefail 0 |
531 | #endif | 554 | #endif |
532 | #if DEBUG | 555 | #if DEBUG |
533 | # define nolog optlist[14 + BASH_PIPEFAIL] | 556 | # define nolog optlist[15 + BASH_PIPEFAIL] |
534 | # define debug optlist[15 + BASH_PIPEFAIL] | 557 | # define debug optlist[16 + BASH_PIPEFAIL] |
535 | #endif | 558 | #endif |
536 | #if ENABLE_PLATFORM_MINGW32 | 559 | #if ENABLE_PLATFORM_MINGW32 |
537 | # define winxp optlist[14 + BASH_PIPEFAIL + 2*DEBUG] | 560 | # define winxp optlist[14 + BASH_PIPEFAIL + 2*DEBUG] |
@@ -10156,8 +10179,8 @@ setinteractive(int on) | |||
10156 | setsignal(SIGINT); | 10179 | setsignal(SIGINT); |
10157 | setsignal(SIGQUIT); | 10180 | setsignal(SIGQUIT); |
10158 | setsignal(SIGTERM); | 10181 | setsignal(SIGTERM); |
10159 | #if !ENABLE_FEATURE_SH_EXTRA_QUIET | ||
10160 | if (is_interactive > 1) { | 10182 | if (is_interactive > 1) { |
10183 | #if !ENABLE_FEATURE_SH_EXTRA_QUIET | ||
10161 | /* Looks like they want an interactive shell */ | 10184 | /* Looks like they want an interactive shell */ |
10162 | static smallint did_banner; | 10185 | static smallint did_banner; |
10163 | 10186 | ||
@@ -10171,8 +10194,12 @@ setinteractive(int on) | |||
10171 | ); | 10194 | ); |
10172 | did_banner = 1; | 10195 | did_banner = 1; |
10173 | } | 10196 | } |
10174 | } | ||
10175 | #endif | 10197 | #endif |
10198 | #if ENABLE_FEATURE_EDITING | ||
10199 | if (!line_input_state) | ||
10200 | line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); | ||
10201 | #endif | ||
10202 | } | ||
10176 | } | 10203 | } |
10177 | 10204 | ||
10178 | static void | 10205 | static void |
@@ -10184,10 +10211,12 @@ optschanged(void) | |||
10184 | setinteractive(iflag); | 10211 | setinteractive(iflag); |
10185 | setjobctl(mflag); | 10212 | setjobctl(mflag); |
10186 | #if ENABLE_FEATURE_EDITING_VI | 10213 | #if ENABLE_FEATURE_EDITING_VI |
10187 | if (viflag) | 10214 | if (line_input_state) { |
10188 | line_input_state->flags |= VI_MODE; | 10215 | if (viflag) |
10189 | else | 10216 | line_input_state->flags |= VI_MODE; |
10190 | line_input_state->flags &= ~VI_MODE; | 10217 | else |
10218 | line_input_state->flags &= ~VI_MODE; | ||
10219 | } | ||
10191 | #else | 10220 | #else |
10192 | viflag = 0; /* forcibly keep the option off */ | 10221 | viflag = 0; /* forcibly keep the option off */ |
10193 | #endif | 10222 | #endif |
@@ -11203,13 +11232,11 @@ preadfd(void) | |||
11203 | else { | 11232 | else { |
11204 | # if ENABLE_ASH_IDLE_TIMEOUT | 11233 | # if ENABLE_ASH_IDLE_TIMEOUT |
11205 | int timeout = -1; | 11234 | int timeout = -1; |
11206 | if (iflag) { | 11235 | const char *tmout_var = lookupvar("TMOUT"); |
11207 | const char *tmout_var = lookupvar("TMOUT"); | 11236 | if (tmout_var) { |
11208 | if (tmout_var) { | 11237 | timeout = atoi(tmout_var) * 1000; |
11209 | timeout = atoi(tmout_var) * 1000; | 11238 | if (timeout <= 0) |
11210 | if (timeout <= 0) | 11239 | timeout = -1; |
11211 | timeout = -1; | ||
11212 | } | ||
11213 | } | 11240 | } |
11214 | line_input_state->timeout = timeout; | 11241 | line_input_state->timeout = timeout; |
11215 | # endif | 11242 | # endif |
@@ -11750,6 +11777,8 @@ plus_minus_o(char *name, int val) | |||
11750 | return 1; | 11777 | return 1; |
11751 | } | 11778 | } |
11752 | for (i = 0; i < NOPTS; i++) { | 11779 | for (i = 0; i < NOPTS; i++) { |
11780 | if (optnames(i)[0] == '\0') | ||
11781 | continue; | ||
11753 | if (val) { | 11782 | if (val) { |
11754 | out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off"); | 11783 | out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off"); |
11755 | } else { | 11784 | } else { |
@@ -11764,7 +11793,7 @@ setoption(int flag, int val) | |||
11764 | int i; | 11793 | int i; |
11765 | 11794 | ||
11766 | for (i = 0; i < NOPTS; i++) { | 11795 | for (i = 0; i < NOPTS; i++) { |
11767 | if (optletters(i) == flag) { | 11796 | if (optletters(i) == flag && optnames(i)[0] != '\0') { |
11768 | optlist[i] = val; | 11797 | optlist[i] = val; |
11769 | return; | 11798 | return; |
11770 | } | 11799 | } |
@@ -11772,14 +11801,17 @@ setoption(int flag, int val) | |||
11772 | ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag); | 11801 | ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag); |
11773 | /* NOTREACHED */ | 11802 | /* NOTREACHED */ |
11774 | } | 11803 | } |
11804 | /* If login_sh is not NULL, we are called to parse command line opts, | ||
11805 | * not "set -opts" | ||
11806 | */ | ||
11775 | static int | 11807 | static int |
11776 | options(int cmdline, int *login_sh) | 11808 | options(int *login_sh) |
11777 | { | 11809 | { |
11778 | char *p; | 11810 | char *p; |
11779 | int val; | 11811 | int val; |
11780 | int c; | 11812 | int c; |
11781 | 11813 | ||
11782 | if (cmdline) { | 11814 | if (login_sh) { |
11783 | minusc = NULL; | 11815 | minusc = NULL; |
11784 | #if ENABLE_PLATFORM_MINGW32 | 11816 | #if ENABLE_PLATFORM_MINGW32 |
11785 | dirarg = NULL; | 11817 | dirarg = NULL; |
@@ -11795,7 +11827,7 @@ options(int cmdline, int *login_sh) | |||
11795 | if (c == '-') { | 11827 | if (c == '-') { |
11796 | val = 1; | 11828 | val = 1; |
11797 | if (p[0] == '\0' || LONE_DASH(p)) { | 11829 | if (p[0] == '\0' || LONE_DASH(p)) { |
11798 | if (!cmdline) { | 11830 | if (!login_sh) { |
11799 | /* "-" means turn off -x and -v */ | 11831 | /* "-" means turn off -x and -v */ |
11800 | if (p[0] == '\0') | 11832 | if (p[0] == '\0') |
11801 | xflag = vflag = 0; | 11833 | xflag = vflag = 0; |
@@ -11808,40 +11840,58 @@ options(int cmdline, int *login_sh) | |||
11808 | } | 11840 | } |
11809 | /* first char was + or - */ | 11841 | /* first char was + or - */ |
11810 | while ((c = *p++) != '\0') { | 11842 | while ((c = *p++) != '\0') { |
11811 | /* bash 3.2 indeed handles -c CMD and +c CMD the same */ | 11843 | if (login_sh) { |
11812 | if (c == 'c' && cmdline) { | 11844 | /* bash 3.2 indeed handles -c CMD and +c CMD the same */ |
11813 | minusc = p; /* command is after shell args */ | 11845 | if (c == 'c') { |
11846 | minusc = p; /* command is after shell args */ | ||
11847 | cflag = 1; | ||
11848 | continue; | ||
11849 | } | ||
11814 | #if ENABLE_PLATFORM_MINGW32 | 11850 | #if ENABLE_PLATFORM_MINGW32 |
11815 | /* Undocumented flags; | 11851 | /* Undocumented flags; |
11816 | * -d force current directory | 11852 | * -d force current directory |
11817 | * -t title to display in console window | 11853 | * -t title to display in console window |
11818 | * Must appear before -s or -c. */ | 11854 | * Must appear before -s or -c. */ |
11819 | } else if (c == 'd' && cmdline && val == 1) { | 11855 | if (c == 'd' && val == 1) { |
11820 | if (*argptr == NULL) | 11856 | if (*argptr == NULL) |
11821 | ash_msg_and_raise_error(bb_msg_requires_arg, "-d"); | 11857 | ash_msg_and_raise_error(bb_msg_requires_arg, "-d"); |
11822 | dirarg = *argptr++; | 11858 | dirarg = *argptr++; |
11823 | } else if (c == 't' && cmdline && val == 1) { | 11859 | continue; |
11824 | if (*argptr == NULL) | 11860 | } |
11825 | ash_msg_and_raise_error(bb_msg_requires_arg, "-t"); | 11861 | if (c == 't' && val == 1) { |
11826 | title = *argptr++; | 11862 | if (*argptr == NULL) |
11827 | #endif | 11863 | ash_msg_and_raise_error(bb_msg_requires_arg, "-t"); |
11828 | } else if (c == 'o') { | 11864 | title = *argptr++; |
11865 | continue; | ||
11866 | } | ||
11867 | #endif | ||
11868 | if (c == 's') { /* -s, +s */ | ||
11869 | sflag = 1; | ||
11870 | continue; | ||
11871 | } | ||
11872 | if (c == 'i') { /* -i, +i */ | ||
11873 | iflag = 1; | ||
11874 | continue; | ||
11875 | } | ||
11876 | if (c == 'l') { | ||
11877 | *login_sh = 1; /* -l or +l == --login */ | ||
11878 | continue; | ||
11879 | } | ||
11880 | /* bash does not accept +-login, we also won't */ | ||
11881 | if (val && (c == '-')) { /* long options */ | ||
11882 | if (strcmp(p, "login") == 0) { | ||
11883 | *login_sh = 1; | ||
11884 | } | ||
11885 | break; | ||
11886 | } | ||
11887 | } | ||
11888 | if (c == 'o') { | ||
11829 | if (plus_minus_o(*argptr, val)) { | 11889 | if (plus_minus_o(*argptr, val)) { |
11830 | /* it already printed err message */ | 11890 | /* it already printed err message */ |
11831 | return 1; /* error */ | 11891 | return 1; /* error */ |
11832 | } | 11892 | } |
11833 | if (*argptr) | 11893 | if (*argptr) |
11834 | argptr++; | 11894 | argptr++; |
11835 | } else if (cmdline && (c == 'l')) { /* -l or +l == --login */ | ||
11836 | if (login_sh) | ||
11837 | *login_sh = 1; | ||
11838 | /* bash does not accept +-login, we also won't */ | ||
11839 | } else if (cmdline && val && (c == '-')) { /* long options */ | ||
11840 | if (strcmp(p, "login") == 0) { | ||
11841 | if (login_sh) | ||
11842 | *login_sh = 1; | ||
11843 | } | ||
11844 | break; | ||
11845 | } else { | 11895 | } else { |
11846 | setoption(c, val); | 11896 | setoption(c, val); |
11847 | } | 11897 | } |
@@ -11932,7 +11982,7 @@ setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
11932 | return showvars(nullstr, 0, VUNSET); | 11982 | return showvars(nullstr, 0, VUNSET); |
11933 | 11983 | ||
11934 | INT_OFF; | 11984 | INT_OFF; |
11935 | retval = options(/*cmdline:*/ 0, NULL); | 11985 | retval = options(/*login_sh:*/ NULL); |
11936 | if (retval == 0) { /* if no parse error... */ | 11986 | if (retval == 0) { /* if no parse error... */ |
11937 | optschanged(); | 11987 | optschanged(); |
11938 | if (*argptr != NULL) { | 11988 | if (*argptr != NULL) { |
@@ -13787,6 +13837,8 @@ expandstr(const char *ps, int syntax_type) | |||
13787 | if (setjmp(jmploc.loc) == 0) { | 13837 | if (setjmp(jmploc.loc) == 0) { |
13788 | exception_handler = &jmploc; | 13838 | exception_handler = &jmploc; |
13789 | expandarg(&n, NULL, EXP_QUOTED); | 13839 | expandarg(&n, NULL, EXP_QUOTED); |
13840 | } else if (exception_type == EXEXIT) { | ||
13841 | exitshell(); | ||
13790 | } | 13842 | } |
13791 | exception_handler = savehandler; | 13843 | exception_handler = savehandler; |
13792 | RESTORE_INT(saveint); | 13844 | RESTORE_INT(saveint); |
@@ -14400,7 +14452,8 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14400 | static int FAST_FUNC | 14452 | static int FAST_FUNC |
14401 | historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 14453 | historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) |
14402 | { | 14454 | { |
14403 | show_history(line_input_state); | 14455 | if (line_input_state) |
14456 | show_history(line_input_state); | ||
14404 | return EXIT_SUCCESS; | 14457 | return EXIT_SUCCESS; |
14405 | } | 14458 | } |
14406 | #endif | 14459 | #endif |
@@ -14719,7 +14772,8 @@ exitshell(void) | |||
14719 | int status; | 14772 | int status; |
14720 | 14773 | ||
14721 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT | 14774 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT |
14722 | save_history(line_input_state); | 14775 | if (line_input_state) |
14776 | save_history(line_input_state); | ||
14723 | #endif | 14777 | #endif |
14724 | status = exitstatus; | 14778 | status = exitstatus; |
14725 | TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); | 14779 | TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); |
@@ -14923,7 +14977,7 @@ procargs(char **argv) | |||
14923 | argptr = xargv; | 14977 | argptr = xargv; |
14924 | for (i = 0; i < NOPTS; i++) | 14978 | for (i = 0; i < NOPTS; i++) |
14925 | optlist[i] = 2; | 14979 | optlist[i] = 2; |
14926 | if (options(/*cmdline:*/ 1, &login_sh)) { | 14980 | if (options(&login_sh)) { |
14927 | /* it already printed err message */ | 14981 | /* it already printed err message */ |
14928 | raise_exception(EXERROR); | 14982 | raise_exception(EXERROR); |
14929 | } | 14983 | } |
@@ -14934,8 +14988,13 @@ procargs(char **argv) | |||
14934 | ash_msg_and_raise_error(bb_msg_requires_arg, "-c"); | 14988 | ash_msg_and_raise_error(bb_msg_requires_arg, "-c"); |
14935 | sflag = 1; | 14989 | sflag = 1; |
14936 | } | 14990 | } |
14937 | if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) | 14991 | if (iflag == 2 /* no explicit -i given */ |
14992 | && sflag == 1 /* -s given (or implied) */ | ||
14993 | && !minusc /* bash compat: ash -sc 'echo $-' is not interactive (dash is) */ | ||
14994 | && isatty(0) && isatty(1) /* we are on tty */ | ||
14995 | ) { | ||
14938 | iflag = 1; | 14996 | iflag = 1; |
14997 | } | ||
14939 | if (mflag == 2) | 14998 | if (mflag == 2) |
14940 | mflag = iflag; | 14999 | mflag = iflag; |
14941 | for (i = 0; i < NOPTS; i++) | 15000 | for (i = 0; i < NOPTS; i++) |
@@ -15055,9 +15114,6 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
15055 | monitor(4, etext, profile_buf, sizeof(profile_buf), 50); | 15114 | monitor(4, etext, profile_buf, sizeof(profile_buf), 50); |
15056 | #endif | 15115 | #endif |
15057 | 15116 | ||
15058 | #if ENABLE_FEATURE_EDITING | ||
15059 | line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); | ||
15060 | #endif | ||
15061 | state = 0; | 15117 | state = 0; |
15062 | if (setjmp(jmploc.loc)) { | 15118 | if (setjmp(jmploc.loc)) { |
15063 | smallint e; | 15119 | smallint e; |
@@ -15188,10 +15244,17 @@ int ash_main(int argc UNUSED_PARAM, char **argv) | |||
15188 | * Ensure we don't falsely claim that 0 (stdin) | 15244 | * Ensure we don't falsely claim that 0 (stdin) |
15189 | * is one of stacked source fds. | 15245 | * is one of stacked source fds. |
15190 | * Testcase: ash -c 'exec 1>&0' must not complain. */ | 15246 | * Testcase: ash -c 'exec 1>&0' must not complain. */ |
15247 | |||
15191 | // if (!sflag) g_parsefile->pf_fd = -1; | 15248 | // if (!sflag) g_parsefile->pf_fd = -1; |
15192 | // ^^ not necessary since now we special-case fd 0 | 15249 | // ^^ not necessary since now we special-case fd 0 |
15193 | // in save_fd_on_redirect() | 15250 | // in save_fd_on_redirect() |
15194 | evalstring(minusc, sflag ? 0 : EV_EXIT); | 15251 | |
15252 | // dash: evalstring(minusc, sflag ? 0 : EV_EXIT); | ||
15253 | // The above makes | ||
15254 | // ash -sc 'echo $-' | ||
15255 | // continue reading input from stdin after running 'echo'. | ||
15256 | // bash does not do this: it prints "hBcs" and exits. | ||
15257 | evalstring(minusc, EV_EXIT); | ||
15195 | } | 15258 | } |
15196 | 15259 | ||
15197 | if (sflag || minusc == NULL) { | 15260 | if (sflag || minusc == NULL) { |