aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/ash.c111
-rw-r--r--shell/ash_test/ash-vars/var1.right6
-rwxr-xr-xshell/ash_test/ash-vars/var1.tests14
-rw-r--r--shell/ash_test/ash-vars/var2.right1
-rwxr-xr-xshell/ash_test/ash-vars/var2.tests1
-rwxr-xr-xshell/ash_test/run-all2
6 files changed, 96 insertions, 39 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 10eb90d30..4f9caa434 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -42,19 +42,18 @@
42 * a quit signal will generate a core dump. 42 * a quit signal will generate a core dump.
43 */ 43 */
44#define DEBUG 0 44#define DEBUG 0
45#define IFS_BROKEN
46#define PROFILE 0 45#define PROFILE 0
47#if ENABLE_ASH_JOB_CONTROL 46
48#define JOBS 1 47#define IFS_BROKEN
49#else 48
50#define JOBS 0 49#define JOBS ENABLE_ASH_JOB_CONTROL
51#endif
52 50
53#if DEBUG 51#if DEBUG
54#ifndef _GNU_SOURCE 52#ifndef _GNU_SOURCE
55#define _GNU_SOURCE 53#define _GNU_SOURCE
56#endif 54#endif
57#endif 55#endif
56
58#include "busybox.h" /* for applet_names */ 57#include "busybox.h" /* for applet_names */
59#include <paths.h> 58#include <paths.h>
60#include <setjmp.h> 59#include <setjmp.h>
@@ -5501,15 +5500,19 @@ expari(int quotes)
5501#endif 5500#endif
5502 5501
5503/* argstr needs it */ 5502/* argstr needs it */
5504static char *evalvar(char *p, int flag); 5503static char *evalvar(char *p, int flag, struct strlist *var_str_list);
5505 5504
5506/* 5505/*
5507 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC 5506 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
5508 * characters to allow for further processing. Otherwise treat 5507 * characters to allow for further processing. Otherwise treat
5509 * $@ like $* since no splitting will be performed. 5508 * $@ like $* since no splitting will be performed.
5509 *
5510 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
5511 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
5512 * for correct expansion of "B=$A" word.
5510 */ 5513 */
5511static void 5514static void
5512argstr(char *p, int flag) 5515argstr(char *p, int flag, struct strlist *var_str_list)
5513{ 5516{
5514 static const char spclchars[] ALIGN1 = { 5517 static const char spclchars[] ALIGN1 = {
5515 '=', 5518 '=',
@@ -5611,7 +5614,7 @@ argstr(char *p, int flag)
5611 p[5] == CTLQUOTEMARK 5614 p[5] == CTLQUOTEMARK
5612 )) 5615 ))
5613 ) { 5616 ) {
5614 p = evalvar(p + 1, flag) + 1; 5617 p = evalvar(p + 1, flag, /* var_str_list: */ NULL) + 1;
5615 goto start; 5618 goto start;
5616 } 5619 }
5617 inquotes = !inquotes; 5620 inquotes = !inquotes;
@@ -5627,7 +5630,7 @@ argstr(char *p, int flag)
5627 length++; 5630 length++;
5628 goto addquote; 5631 goto addquote;
5629 case CTLVAR: 5632 case CTLVAR:
5630 p = evalvar(p, flag); 5633 p = evalvar(p, flag, var_str_list);
5631 goto start; 5634 goto start;
5632 case CTLBACKQ: 5635 case CTLBACKQ:
5633 c = 0; 5636 c = 0;
@@ -5731,7 +5734,8 @@ varunset(const char *end, const char *var, const char *umsg, int varflags)
5731} 5734}
5732 5735
5733static const char * 5736static const char *
5734subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes) 5737subevalvar(char *p, char *str, int strloc, int subtype,
5738 int startloc, int varflags, int quotes, struct strlist *var_str_list)
5735{ 5739{
5736 char *startp; 5740 char *startp;
5737 char *loc; 5741 char *loc;
@@ -5743,7 +5747,8 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varfla
5743 char *(*scan)(char *, char *, char *, char *, int , int); 5747 char *(*scan)(char *, char *, char *, char *, int , int);
5744 5748
5745 herefd = -1; 5749 herefd = -1;
5746 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); 5750 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
5751 var_str_list);
5747 STPUTC('\0', expdest); 5752 STPUTC('\0', expdest);
5748 herefd = saveherefd; 5753 herefd = saveherefd;
5749 argbackq = saveargbackq; 5754 argbackq = saveargbackq;
@@ -5802,7 +5807,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varfla
5802 * Add the value of a specialized variable to the stack string. 5807 * Add the value of a specialized variable to the stack string.
5803 */ 5808 */
5804static ssize_t 5809static ssize_t
5805varvalue(char *name, int varflags, int flags) 5810varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
5806{ 5811{
5807 int num; 5812 int num;
5808 char *p; 5813 char *p;
@@ -5899,6 +5904,30 @@ varvalue(char *name, int varflags, int flags)
5899 p = num ? shellparam.p[num - 1] : arg0; 5904 p = num ? shellparam.p[num - 1] : arg0;
5900 goto value; 5905 goto value;
5901 default: 5906 default:
5907 /* NB: name has form "VAR=..." */
5908
5909 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
5910 * which should be considered before we check variables. */
5911 if (var_str_list) {
5912 unsigned name_len = (strchrnul(name, '=') - name) + 1;
5913 p = NULL;
5914 do {
5915 char *str = var_str_list->text;
5916 char *eq = strchr(str, '=');
5917 if (!eq) /* stop at first non-assignment */
5918 break;
5919 eq++;
5920 if (name_len == (eq - str)
5921 && strncmp(str, name, name_len) == 0) {
5922 p = eq;
5923 /* goto value; - WRONG! */
5924 /* think "A=1 A=2 B=$A" */
5925 }
5926 var_str_list = var_str_list->next;
5927 } while (var_str_list);
5928 if (p)
5929 goto value;
5930 }
5902 p = lookupvar(name); 5931 p = lookupvar(name);
5903 value: 5932 value:
5904 if (!p) 5933 if (!p)
@@ -5920,20 +5949,17 @@ varvalue(char *name, int varflags, int flags)
5920 * input string. 5949 * input string.
5921 */ 5950 */
5922static char * 5951static char *
5923evalvar(char *p, int flag) 5952evalvar(char *p, int flag, struct strlist *var_str_list)
5924{ 5953{
5925 int subtype; 5954 char varflags;
5926 int varflags; 5955 char subtype;
5956 char quoted;
5957 char easy;
5927 char *var; 5958 char *var;
5928 int patloc; 5959 int patloc;
5929 int c;
5930 int startloc; 5960 int startloc;
5931 ssize_t varlen; 5961 ssize_t varlen;
5932 int easy;
5933 int quotes;
5934 int quoted;
5935 5962
5936 quotes = flag & (EXP_FULL | EXP_CASE);
5937 varflags = *p++; 5963 varflags = *p++;
5938 subtype = varflags & VSTYPE; 5964 subtype = varflags & VSTYPE;
5939 quoted = varflags & VSQUOTE; 5965 quoted = varflags & VSQUOTE;
@@ -5943,7 +5969,7 @@ evalvar(char *p, int flag)
5943 p = strchr(p, '=') + 1; 5969 p = strchr(p, '=') + 1;
5944 5970
5945 again: 5971 again:
5946 varlen = varvalue(var, varflags, flag); 5972 varlen = varvalue(var, varflags, flag, var_str_list);
5947 if (varflags & VSNUL) 5973 if (varflags & VSNUL)
5948 varlen--; 5974 varlen--;
5949 5975
@@ -5957,7 +5983,8 @@ evalvar(char *p, int flag)
5957 if (varlen < 0) { 5983 if (varlen < 0) {
5958 argstr( 5984 argstr(
5959 p, flag | EXP_TILDE | 5985 p, flag | EXP_TILDE |
5960 (quoted ? EXP_QWORD : EXP_WORD) 5986 (quoted ? EXP_QWORD : EXP_WORD),
5987 var_str_list
5961 ); 5988 );
5962 goto end; 5989 goto end;
5963 } 5990 }
@@ -5968,7 +5995,11 @@ evalvar(char *p, int flag)
5968 5995
5969 if (subtype == VSASSIGN || subtype == VSQUESTION) { 5996 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5970 if (varlen < 0) { 5997 if (varlen < 0) {
5971 if (subevalvar(p, var, 0, subtype, startloc, varflags, 0)) { 5998 if (subevalvar(p, var, /* strloc: */ 0,
5999 subtype, startloc, varflags,
6000 /* quotes: */ 0,
6001 var_str_list)
6002 ) {
5972 varflags &= ~VSNUL; 6003 varflags &= ~VSNUL;
5973 /* 6004 /*
5974 * Remove any recorded regions beyond 6005 * Remove any recorded regions beyond
@@ -5993,10 +6024,8 @@ evalvar(char *p, int flag)
5993 } 6024 }
5994 6025
5995 if (subtype == VSNORMAL) { 6026 if (subtype == VSNORMAL) {
5996 if (!easy) 6027 if (easy)
5997 goto end; 6028 goto record;
5998 record:
5999 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6000 goto end; 6029 goto end;
6001 } 6030 }
6002 6031
@@ -6019,8 +6048,11 @@ evalvar(char *p, int flag)
6019 */ 6048 */
6020 STPUTC('\0', expdest); 6049 STPUTC('\0', expdest);
6021 patloc = expdest - (char *)stackblock(); 6050 patloc = expdest - (char *)stackblock();
6022 if (subevalvar(p, NULL, patloc, subtype, 6051 if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype,
6023 startloc, varflags, quotes) == 0) { 6052 startloc, varflags,
6053 /* quotes: */ flag & (EXP_FULL | EXP_CASE),
6054 var_str_list)
6055 ) {
6024 int amount = expdest - ( 6056 int amount = expdest - (
6025 (char *)stackblock() + patloc - 1 6057 (char *)stackblock() + patloc - 1
6026 ); 6058 );
@@ -6028,14 +6060,15 @@ evalvar(char *p, int flag)
6028 } 6060 }
6029 /* Remove any recorded regions beyond start of variable */ 6061 /* Remove any recorded regions beyond start of variable */
6030 removerecordregions(startloc); 6062 removerecordregions(startloc);
6031 goto record; 6063 record:
6064 recordregion(startloc, expdest - (char *)stackblock(), quoted);
6032 } 6065 }
6033 6066
6034 end: 6067 end:
6035 if (subtype != VSNORMAL) { /* skip to end of alternative */ 6068 if (subtype != VSNORMAL) { /* skip to end of alternative */
6036 int nesting = 1; 6069 int nesting = 1;
6037 for (;;) { 6070 for (;;) {
6038 c = *p++; 6071 char c = *p++;
6039 if (c == CTLESC) 6072 if (c == CTLESC)
6040 p++; 6073 p++;
6041 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 6074 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
@@ -6420,7 +6453,8 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
6420 STARTSTACKSTR(expdest); 6453 STARTSTACKSTR(expdest);
6421 ifsfirst.next = NULL; 6454 ifsfirst.next = NULL;
6422 ifslastp = NULL; 6455 ifslastp = NULL;
6423 argstr(arg->narg.text, flag); 6456 argstr(arg->narg.text, flag,
6457 /* var_str_list: */ arglist ? arglist->list : NULL);
6424 p = _STPUTC('\0', expdest); 6458 p = _STPUTC('\0', expdest);
6425 expdest = p - 1; 6459 expdest = p - 1;
6426 if (arglist == NULL) { 6460 if (arglist == NULL) {
@@ -6486,7 +6520,8 @@ casematch(union node *pattern, char *val)
6486 argbackq = pattern->narg.backquote; 6520 argbackq = pattern->narg.backquote;
6487 STARTSTACKSTR(expdest); 6521 STARTSTACKSTR(expdest);
6488 ifslastp = NULL; 6522 ifslastp = NULL;
6489 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 6523 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
6524 /* var_str_list: */ NULL);
6490 STACKSTRNUL(expdest); 6525 STACKSTRNUL(expdest);
6491 result = patmatch(stackblock(), val); 6526 result = patmatch(stackblock(), val);
6492 popstackmark(&smark); 6527 popstackmark(&smark);
@@ -8249,8 +8284,8 @@ bltincmd(int argc, char **argv)
8249static void 8284static void
8250evalcommand(union node *cmd, int flags) 8285evalcommand(union node *cmd, int flags)
8251{ 8286{
8252 static const struct builtincmd bltin = { 8287 static const struct builtincmd null_bltin = {
8253 "\0\0", bltincmd 8288 "\0\0", bltincmd /* why three NULs? */
8254 }; 8289 };
8255 struct stackmark smark; 8290 struct stackmark smark;
8256 union node *argp; 8291 union node *argp;
@@ -8276,7 +8311,7 @@ evalcommand(union node *cmd, int flags)
8276 back_exitstatus = 0; 8311 back_exitstatus = 0;
8277 8312
8278 cmdentry.cmdtype = CMDBUILTIN; 8313 cmdentry.cmdtype = CMDBUILTIN;
8279 cmdentry.u.cmd = &bltin; 8314 cmdentry.u.cmd = &null_bltin;
8280 varlist.lastp = &varlist.list; 8315 varlist.lastp = &varlist.list;
8281 *varlist.lastp = NULL; 8316 *varlist.lastp = NULL;
8282 arglist.lastp = &arglist.list; 8317 arglist.lastp = &arglist.list;
@@ -8352,7 +8387,7 @@ evalcommand(union node *cmd, int flags)
8352 } 8387 }
8353 sp = arglist.list; 8388 sp = arglist.list;
8354 } 8389 }
8355 full_write(preverrout_fd, "\n", 1); 8390 safe_write(preverrout_fd, "\n", 1);
8356 } 8391 }
8357 8392
8358 cmd_is_exec = 0; 8393 cmd_is_exec = 0;
diff --git a/shell/ash_test/ash-vars/var1.right b/shell/ash_test/ash-vars/var1.right
new file mode 100644
index 000000000..2a01291bb
--- /dev/null
+++ b/shell/ash_test/ash-vars/var1.right
@@ -0,0 +1,6 @@
1a=a A=a
2a=a A=a
3a= A=
4a= A=
5a=a A=a
6a=a A=a
diff --git a/shell/ash_test/ash-vars/var1.tests b/shell/ash_test/ash-vars/var1.tests
new file mode 100755
index 000000000..802e489bd
--- /dev/null
+++ b/shell/ash_test/ash-vars/var1.tests
@@ -0,0 +1,14 @@
1# check that first assignment has proper effect on second one
2
3(
4a=a A=$a
5echo a=$a A=$A
6)
7(a=a A=$a; echo a=$a A=$A)
8(a=a A=$a echo a=$a A=$A)
9(a=a A=$a /bin/echo a=$a A=$A)
10
11f() { echo a=$a A=$A; }
12
13(a=a A=$a f)
14(a=a A=$a; f)
diff --git a/shell/ash_test/ash-vars/var2.right b/shell/ash_test/ash-vars/var2.right
new file mode 100644
index 000000000..8fed138eb
--- /dev/null
+++ b/shell/ash_test/ash-vars/var2.right
@@ -0,0 +1 @@
bus/usb/1/2
diff --git a/shell/ash_test/ash-vars/var2.tests b/shell/ash_test/ash-vars/var2.tests
new file mode 100755
index 000000000..07feaeb8b
--- /dev/null
+++ b/shell/ash_test/ash-vars/var2.tests
@@ -0,0 +1 @@
X=usbdev1.2 X=${X#usbdev} B=${X%%.*} D=${X#*.}; echo bus/usb/$B/$D
diff --git a/shell/ash_test/run-all b/shell/ash_test/run-all
index 416900aa2..e02333888 100755
--- a/shell/ash_test/run-all
+++ b/shell/ash_test/run-all
@@ -17,6 +17,7 @@ export THIS_SH
17do_test() 17do_test()
18{ 18{
19 test -d "$1" || return 0 19 test -d "$1" || return 0
20 echo do_test "$1"
20 ( 21 (
21 cd "$1" || { echo "cannot cd $1!"; exit 1; } 22 cd "$1" || { echo "cannot cd $1!"; exit 1; }
22 for x in run-*; do 23 for x in run-*; do
@@ -53,7 +54,6 @@ if [ $# -lt 1 ]; then
53 modules=`ls -d ash-*` 54 modules=`ls -d ash-*`
54 55
55 for module in $modules; do 56 for module in $modules; do
56 echo do_test $module
57 do_test $module 57 do_test $module
58 done 58 done
59else 59else