aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c193
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
10178static void 10205static 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 */
11775static int 11807static int
11776options(int cmdline, int *login_sh) 11808options(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)
14400static int FAST_FUNC 14452static int FAST_FUNC
14401historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 14453historycmd(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) {