diff options
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 109 |
1 files changed, 71 insertions, 38 deletions
diff --git a/shell/ash.c b/shell/ash.c index 5debd82f2..6cc29d25e 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -2566,12 +2566,8 @@ putprompt(const char *s) | |||
2566 | } | 2566 | } |
2567 | #endif | 2567 | #endif |
2568 | 2568 | ||
2569 | #if ENABLE_ASH_EXPAND_PRMT | ||
2570 | /* expandstr() needs parsing machinery, so it is far away ahead... */ | 2569 | /* expandstr() needs parsing machinery, so it is far away ahead... */ |
2571 | static const char *expandstr(const char *ps); | 2570 | static const char *expandstr(const char *ps); |
2572 | #else | ||
2573 | #define expandstr(s) s | ||
2574 | #endif | ||
2575 | 2571 | ||
2576 | static void | 2572 | static void |
2577 | setprompt_if(smallint do_set, int whichprompt) | 2573 | setprompt_if(smallint do_set, int whichprompt) |
@@ -2596,10 +2592,10 @@ setprompt_if(smallint do_set, int whichprompt) | |||
2596 | } | 2592 | } |
2597 | #if ENABLE_ASH_EXPAND_PRMT | 2593 | #if ENABLE_ASH_EXPAND_PRMT |
2598 | pushstackmark(&smark, stackblocksize()); | 2594 | pushstackmark(&smark, stackblocksize()); |
2599 | #endif | ||
2600 | putprompt(expandstr(prompt)); | 2595 | putprompt(expandstr(prompt)); |
2601 | #if ENABLE_ASH_EXPAND_PRMT | ||
2602 | popstackmark(&smark); | 2596 | popstackmark(&smark); |
2597 | #else | ||
2598 | putprompt(prompt); | ||
2603 | #endif | 2599 | #endif |
2604 | } | 2600 | } |
2605 | 2601 | ||
@@ -4244,15 +4240,19 @@ sprint_status48(char *s, int status, int sigonly) | |||
4244 | 4240 | ||
4245 | col = 0; | 4241 | col = 0; |
4246 | if (!WIFEXITED(status)) { | 4242 | if (!WIFEXITED(status)) { |
4247 | if (JOBS && WIFSTOPPED(status)) | 4243 | #if JOBS |
4244 | if (WIFSTOPPED(status)) | ||
4248 | st = WSTOPSIG(status); | 4245 | st = WSTOPSIG(status); |
4249 | else | 4246 | else |
4247 | #endif | ||
4250 | st = WTERMSIG(status); | 4248 | st = WTERMSIG(status); |
4251 | if (sigonly) { | 4249 | if (sigonly) { |
4252 | if (st == SIGINT || st == SIGPIPE) | 4250 | if (st == SIGINT || st == SIGPIPE) |
4253 | goto out; | 4251 | goto out; |
4254 | if (JOBS && WIFSTOPPED(status)) | 4252 | #if JOBS |
4253 | if (WIFSTOPPED(status)) | ||
4255 | goto out; | 4254 | goto out; |
4255 | #endif | ||
4256 | } | 4256 | } |
4257 | st &= 0x7f; | 4257 | st &= 0x7f; |
4258 | //TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata | 4258 | //TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata |
@@ -4501,8 +4501,10 @@ dowait(int block, struct job *job) | |||
4501 | goto out; | 4501 | goto out; |
4502 | } | 4502 | } |
4503 | /* The process wasn't found in job list */ | 4503 | /* The process wasn't found in job list */ |
4504 | if (JOBS && !WIFSTOPPED(status)) | 4504 | #if JOBS |
4505 | if (!WIFSTOPPED(status)) | ||
4505 | jobless--; | 4506 | jobless--; |
4507 | #endif | ||
4506 | out: | 4508 | out: |
4507 | INT_ON; | 4509 | INT_ON; |
4508 | 4510 | ||
@@ -6285,6 +6287,7 @@ rmescapes(char *str, int flag) | |||
6285 | while (*p) { | 6287 | while (*p) { |
6286 | if ((unsigned char)*p == CTLQUOTEMARK) { | 6288 | if ((unsigned char)*p == CTLQUOTEMARK) { |
6287 | // Note: both inquotes and protect_against_glob only affect whether | 6289 | // Note: both inquotes and protect_against_glob only affect whether |
6290 | // CTLESC,<ch> gets converted to <ch> or to \<ch> | ||
6288 | inquotes = ~inquotes; | 6291 | inquotes = ~inquotes; |
6289 | p++; | 6292 | p++; |
6290 | protect_against_glob = globbing; | 6293 | protect_against_glob = globbing; |
@@ -6297,7 +6300,33 @@ rmescapes(char *str, int flag) | |||
6297 | ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)"); | 6300 | ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)"); |
6298 | #endif | 6301 | #endif |
6299 | if (protect_against_glob) { | 6302 | if (protect_against_glob) { |
6300 | *q++ = '\\'; | 6303 | /* |
6304 | * We used to trust glob() and fnmatch() to eat | ||
6305 | * superfluous escapes (\z where z has no | ||
6306 | * special meaning anyway). But this causes | ||
6307 | * bugs such as string of one greek letter rho | ||
6308 | * (unicode-encoded as two bytes "cf,81") | ||
6309 | * getting encoded as "cf,CTLESC,81" | ||
6310 | * and here, converted to "cf,\,81" - | ||
6311 | * which does not go well with some flavors | ||
6312 | * of fnmatch() in unicode locales | ||
6313 | * (for example, glibc <= 2.22). | ||
6314 | * | ||
6315 | * Lets add "\" only on the chars which need it. | ||
6316 | * Testcases for less obvious chars are shown. | ||
6317 | */ | ||
6318 | if (*p == '*' | ||
6319 | || *p == '?' | ||
6320 | || *p == '[' | ||
6321 | || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */ | ||
6322 | || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */ | ||
6323 | || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */ | ||
6324 | || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */ | ||
6325 | /* Some libc support [^negate], that's why "^" also needs love */ | ||
6326 | || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */ | ||
6327 | ) { | ||
6328 | *q++ = '\\'; | ||
6329 | } | ||
6301 | } | 6330 | } |
6302 | } else if (*p == '\\' && !inquotes) { | 6331 | } else if (*p == '\\' && !inquotes) { |
6303 | /* naked back slash */ | 6332 | /* naked back slash */ |
@@ -6963,7 +6992,6 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6963 | char *loc; | 6992 | char *loc; |
6964 | char *rmesc, *rmescend; | 6993 | char *rmesc, *rmescend; |
6965 | char *str; | 6994 | char *str; |
6966 | IF_BASH_SUBSTR(int pos, len, orig_len;) | ||
6967 | int amount, resetloc; | 6995 | int amount, resetloc; |
6968 | IF_BASH_PATTERN_SUBST(int workloc;) | 6996 | IF_BASH_PATTERN_SUBST(int workloc;) |
6969 | IF_BASH_PATTERN_SUBST(char *repl = NULL;) | 6997 | IF_BASH_PATTERN_SUBST(char *repl = NULL;) |
@@ -6992,14 +7020,23 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6992 | /* NOTREACHED */ | 7020 | /* NOTREACHED */ |
6993 | 7021 | ||
6994 | #if BASH_SUBSTR | 7022 | #if BASH_SUBSTR |
6995 | case VSSUBSTR: | 7023 | case VSSUBSTR: { |
6996 | //TODO: support more general format ${v:EXPR:EXPR}, | 7024 | int pos, len, orig_len; |
6997 | // where EXPR follows $(()) rules | 7025 | char *colon; |
7026 | |||
6998 | loc = str = stackblock() + strloc; | 7027 | loc = str = stackblock() + strloc; |
7028 | |||
7029 | # if !ENABLE_FEATURE_SH_MATH | ||
7030 | # define ash_arith number | ||
7031 | # endif | ||
6999 | /* Read POS in ${var:POS:LEN} */ | 7032 | /* Read POS in ${var:POS:LEN} */ |
7000 | pos = atoi(loc); /* number(loc) errors out on "1:4" */ | 7033 | colon = strchr(loc, ':'); |
7001 | len = str - startp - 1; | 7034 | if (colon) *colon = '\0'; |
7035 | pos = ash_arith(loc); | ||
7036 | if (colon) *colon = ':'; | ||
7002 | 7037 | ||
7038 | /* Read LEN in ${var:POS:LEN} */ | ||
7039 | len = str - startp - 1; | ||
7003 | /* *loc != '\0', guaranteed by parser */ | 7040 | /* *loc != '\0', guaranteed by parser */ |
7004 | if (quotes) { | 7041 | if (quotes) { |
7005 | char *ptr; | 7042 | char *ptr; |
@@ -7013,25 +7050,21 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7013 | } | 7050 | } |
7014 | } | 7051 | } |
7015 | orig_len = len; | 7052 | orig_len = len; |
7016 | |||
7017 | if (*loc++ == ':') { | 7053 | if (*loc++ == ':') { |
7018 | /* ${var::LEN} */ | 7054 | /* ${var::LEN} */ |
7019 | len = number(loc); | 7055 | len = ash_arith(loc); |
7020 | } else { | 7056 | } else { |
7021 | /* Skip POS in ${var:POS:LEN} */ | 7057 | /* Skip POS in ${var:POS:LEN} */ |
7022 | len = orig_len; | 7058 | len = orig_len; |
7023 | while (*loc && *loc != ':') { | 7059 | while (*loc && *loc != ':') { |
7024 | /* TODO? | ||
7025 | * bash complains on: var=qwe; echo ${var:1a:123} | ||
7026 | if (!isdigit(*loc)) | ||
7027 | ash_msg_and_raise_error(msg_illnum, str); | ||
7028 | */ | ||
7029 | loc++; | 7060 | loc++; |
7030 | } | 7061 | } |
7031 | if (*loc++ == ':') { | 7062 | if (*loc++ == ':') { |
7032 | len = number(loc); | 7063 | len = ash_arith(loc); |
7033 | } | 7064 | } |
7034 | } | 7065 | } |
7066 | # undef ash_arith | ||
7067 | |||
7035 | if (pos < 0) { | 7068 | if (pos < 0) { |
7036 | /* ${VAR:$((-n)):l} starts n chars from the end */ | 7069 | /* ${VAR:$((-n)):l} starts n chars from the end */ |
7037 | pos = orig_len + pos; | 7070 | pos = orig_len + pos; |
@@ -7039,12 +7072,16 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7039 | if ((unsigned)pos >= orig_len) { | 7072 | if ((unsigned)pos >= orig_len) { |
7040 | /* apart from obvious ${VAR:999999:l}, | 7073 | /* apart from obvious ${VAR:999999:l}, |
7041 | * covers ${VAR:$((-9999999)):l} - result is "" | 7074 | * covers ${VAR:$((-9999999)):l} - result is "" |
7042 | * (bash-compat) | 7075 | * (bash compat) |
7043 | */ | 7076 | */ |
7044 | pos = 0; | 7077 | pos = 0; |
7045 | len = 0; | 7078 | len = 0; |
7046 | } | 7079 | } |
7047 | if (len > (orig_len - pos)) | 7080 | if (len < 0) { |
7081 | /* ${VAR:N:-M} sets LEN to strlen()-M */ | ||
7082 | len = (orig_len - pos) + len; | ||
7083 | } | ||
7084 | if ((unsigned)len > (orig_len - pos)) | ||
7048 | len = orig_len - pos; | 7085 | len = orig_len - pos; |
7049 | 7086 | ||
7050 | for (str = startp; pos; str++, pos--) { | 7087 | for (str = startp; pos; str++, pos--) { |
@@ -7060,6 +7097,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7060 | amount = loc - expdest; | 7097 | amount = loc - expdest; |
7061 | STADJUST(amount, expdest); | 7098 | STADJUST(amount, expdest); |
7062 | return loc; | 7099 | return loc; |
7100 | } | ||
7063 | #endif /* BASH_SUBSTR */ | 7101 | #endif /* BASH_SUBSTR */ |
7064 | } | 7102 | } |
7065 | 7103 | ||
@@ -7104,6 +7142,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7104 | #if BASH_PATTERN_SUBST | 7142 | #if BASH_PATTERN_SUBST |
7105 | workloc = expdest - (char *)stackblock(); | 7143 | workloc = expdest - (char *)stackblock(); |
7106 | if (subtype == VSREPLACE || subtype == VSREPLACEALL) { | 7144 | if (subtype == VSREPLACE || subtype == VSREPLACEALL) { |
7145 | int len; | ||
7107 | char *idx, *end; | 7146 | char *idx, *end; |
7108 | 7147 | ||
7109 | if (!repl) { | 7148 | if (!repl) { |
@@ -7970,7 +8009,9 @@ expandhere(union node *arg, int fd) | |||
7970 | static int | 8009 | static int |
7971 | patmatch(char *pattern, const char *string) | 8010 | patmatch(char *pattern, const char *string) |
7972 | { | 8011 | { |
7973 | return pmatch(preglob(pattern, 0), string); | 8012 | char *p = preglob(pattern, 0); |
8013 | //bb_error_msg("fnmatch(pattern:'%s',str:'%s')", p, string); | ||
8014 | return pmatch(p, string); | ||
7974 | } | 8015 | } |
7975 | 8016 | ||
7976 | /* | 8017 | /* |
@@ -8072,7 +8113,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** | |||
8072 | clearenv(); | 8113 | clearenv(); |
8073 | while (*envp) | 8114 | while (*envp) |
8074 | putenv(*envp++); | 8115 | putenv(*envp++); |
8075 | run_applet_no_and_exit(applet_no, argv); | 8116 | run_applet_no_and_exit(applet_no, cmd, argv); |
8076 | } | 8117 | } |
8077 | /* re-exec ourselves with the new arguments */ | 8118 | /* re-exec ourselves with the new arguments */ |
8078 | execve(bb_busybox_exec_path, argv, envp); | 8119 | execve(bb_busybox_exec_path, argv, envp); |
@@ -12022,9 +12063,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
12022 | smallint dblquote; | 12063 | smallint dblquote; |
12023 | smallint oldstyle; | 12064 | smallint oldstyle; |
12024 | IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */ | 12065 | IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */ |
12025 | #if ENABLE_ASH_EXPAND_PRMT | ||
12026 | smallint pssyntax; /* we are expanding a prompt string */ | 12066 | smallint pssyntax; /* we are expanding a prompt string */ |
12027 | #endif | ||
12028 | int varnest; /* levels of variables expansion */ | 12067 | int varnest; /* levels of variables expansion */ |
12029 | IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */ | 12068 | IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */ |
12030 | IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */ | 12069 | IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */ |
@@ -12036,11 +12075,9 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
12036 | bqlist = NULL; | 12075 | bqlist = NULL; |
12037 | quotef = 0; | 12076 | quotef = 0; |
12038 | IF_FEATURE_SH_MATH(prevsyntax = 0;) | 12077 | IF_FEATURE_SH_MATH(prevsyntax = 0;) |
12039 | #if ENABLE_ASH_EXPAND_PRMT | ||
12040 | pssyntax = (syntax == PSSYNTAX); | 12078 | pssyntax = (syntax == PSSYNTAX); |
12041 | if (pssyntax) | 12079 | if (pssyntax) |
12042 | syntax = DQSYNTAX; | 12080 | syntax = DQSYNTAX; |
12043 | #endif | ||
12044 | dblquote = (syntax == DQSYNTAX); | 12081 | dblquote = (syntax == DQSYNTAX); |
12045 | varnest = 0; | 12082 | varnest = 0; |
12046 | IF_FEATURE_SH_MATH(arinest = 0;) | 12083 | IF_FEATURE_SH_MATH(arinest = 0;) |
@@ -12094,12 +12131,10 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
12094 | } else if (c == '\n') { | 12131 | } else if (c == '\n') { |
12095 | nlprompt(); | 12132 | nlprompt(); |
12096 | } else { | 12133 | } else { |
12097 | #if ENABLE_ASH_EXPAND_PRMT | ||
12098 | if (c == '$' && pssyntax) { | 12134 | if (c == '$' && pssyntax) { |
12099 | USTPUTC(CTLESC, out); | 12135 | USTPUTC(CTLESC, out); |
12100 | USTPUTC('\\', out); | 12136 | USTPUTC('\\', out); |
12101 | } | 12137 | } |
12102 | #endif | ||
12103 | /* Backslash is retained if we are in "str" and next char isn't special */ | 12138 | /* Backslash is retained if we are in "str" and next char isn't special */ |
12104 | if (dblquote | 12139 | if (dblquote |
12105 | && c != '\\' | 12140 | && c != '\\' |
@@ -12384,7 +12419,7 @@ parsesub: { | |||
12384 | #if ENABLE_FEATURE_SH_MATH | 12419 | #if ENABLE_FEATURE_SH_MATH |
12385 | PARSEARITH(); | 12420 | PARSEARITH(); |
12386 | #else | 12421 | #else |
12387 | raise_error_syntax("you disabled math support for $((arith)) syntax"); | 12422 | raise_error_syntax("support for $((arith)) is disabled"); |
12388 | #endif | 12423 | #endif |
12389 | } else { | 12424 | } else { |
12390 | pungetc(); | 12425 | pungetc(); |
@@ -12933,7 +12968,6 @@ parseheredoc(void) | |||
12933 | /* | 12968 | /* |
12934 | * called by editline -- any expansions to the prompt should be added here. | 12969 | * called by editline -- any expansions to the prompt should be added here. |
12935 | */ | 12970 | */ |
12936 | #if ENABLE_ASH_EXPAND_PRMT | ||
12937 | static const char * | 12971 | static const char * |
12938 | expandstr(const char *ps) | 12972 | expandstr(const char *ps) |
12939 | { | 12973 | { |
@@ -12959,7 +12993,6 @@ expandstr(const char *ps) | |||
12959 | expandarg(&n, NULL, EXP_QUOTED); | 12993 | expandarg(&n, NULL, EXP_QUOTED); |
12960 | return stackblock(); | 12994 | return stackblock(); |
12961 | } | 12995 | } |
12962 | #endif | ||
12963 | 12996 | ||
12964 | /* | 12997 | /* |
12965 | * Execute a command or commands contained in a string. | 12998 | * Execute a command or commands contained in a string. |
@@ -13497,7 +13530,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
13497 | exitcode = 0; | 13530 | exitcode = 0; |
13498 | while (*ap) { | 13531 | while (*ap) { |
13499 | signo = get_signum(*ap); | 13532 | signo = get_signum(*ap); |
13500 | if (signo < 0) { | 13533 | if (signo < 0 || signo >= NSIG) { |
13501 | /* Mimic bash message exactly */ | 13534 | /* Mimic bash message exactly */ |
13502 | ash_msg("%s: invalid signal specification", *ap); | 13535 | ash_msg("%s: invalid signal specification", *ap); |
13503 | exitcode = 1; | 13536 | exitcode = 1; |