ash: [VAR] Move unsetvar functionality into setvareq
Upstream commit:
Date: Tue, 25 May 2010 20:55:05 +0800
[VAR] Move unsetvar functionality into setvareq
This patch moves the unsetvar code into setvareq so that we can
no have a pathological case of an unset variable hanging around
unless it has a bit pinning it like VEXPORT.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
function old new delta
setvareq 227 303 +76
expmeta 517 521 +4
localcmd 364 366 +2
unsetcmd 96 76 -20
unsetvar 129 7 -122
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/2 up/down: 82/-142) Total: -60 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/shell/ash.c b/shell/ash.c
index 0ae086e..72ceba7 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -2269,11 +2269,22 @@
if (!(vp->flags & (VTEXTFIXED|VSTACK)))
free((char*)vp->var_text);
+ if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) | (vp->flags & VSTRFIXED)) == VUNSET) {
+ *vpp = vp->next;
+ free(vp);
+ out_free:
+ if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
+ free(s);
+ return;
+ }
+
flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
} else {
/* variable s is not found */
if (flags & VNOSET)
return;
+ if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
+ goto out_free;
vp = ckzalloc(sizeof(*vp));
vp->next = *vpp;
/*vp->func = NULL; - ckzalloc did it */
@@ -2331,43 +2342,10 @@
/*
* Unset the specified variable.
*/
-static int
+static void
unsetvar(const char *s)
{
- struct var **vpp;
- struct var *vp;
- int retval;
-
- vpp = findvar(hashvar(s), s);
- vp = *vpp;
- retval = 2;
- if (vp) {
- int flags = vp->flags;
-
- retval = 1;
- if (flags & VREADONLY)
- goto out;
-#if ENABLE_ASH_RANDOM_SUPPORT
- vp->flags &= ~VDYNAMIC;
-#endif
- if (flags & VUNSET)
- goto ok;
- if ((flags & VSTRFIXED) == 0) {
- INT_OFF;
- if ((flags & (VTEXTFIXED|VSTACK)) == 0)
- free((char*)vp->var_text);
- *vpp = vp->next;
- free(vp);
- INT_ON;
- } else {
- setvar0(s, NULL);
- vp->flags &= ~VEXPORT;
- }
- ok:
- retval = 0;
- }
- out:
- return retval;
+ setvar0(s, NULL);
}
/*
@@ -13218,7 +13196,6 @@
char **ap;
int i;
int flag = 0;
- int ret = 0;
while ((i = nextopt("vf")) != 0) {
flag = i;
@@ -13226,15 +13203,13 @@
for (ap = argptr; *ap; ap++) {
if (flag != 'f') {
- i = unsetvar(*ap);
- ret |= i;
- if (!(i & 2))
- continue;
+ unsetvar(*ap);
+ continue;
}
if (flag != 'v')
unsetfunc(*ap);
}
- return ret & 1;
+ return 0;
}
static const unsigned char timescmd_str[] ALIGN1 = {
diff --git a/shell/ash_test/ash-vars/readonly0.right b/shell/ash_test/ash-vars/readonly0.right
index f3a6bde..ecc4054 100644
--- a/shell/ash_test/ash-vars/readonly0.right
+++ b/shell/ash_test/ash-vars/readonly0.right
@@ -10,4 +10,4 @@
./readonly0.tests: export: line 27: a: is read only
Fail:2
-Fail:1
+./readonly0.tests: unset: line 44: a: is read only
diff --git a/shell/ash_test/ash-vars/unset.right b/shell/ash_test/ash-vars/unset.right
new file mode 100644
index 0000000..77d5abe
--- /dev/null
+++ b/shell/ash_test/ash-vars/unset.right
@@ -0,0 +1,17 @@
+./unset.tests: unset: line 3: -: bad variable name
+2
+./unset.tests: unset: line 5: illegal option -m
+2
+0
+___
+0 f g
+0 g
+0
+___
+0 f g
+0
+0 f g
+0
+___
+./unset.tests: unset: line 36: VAR_RO: is read only
+2 f g
diff --git a/shell/ash_test/ash-vars/unset.tests b/shell/ash_test/ash-vars/unset.tests
new file mode 100755
index 0000000..11b3927
--- /dev/null
+++ b/shell/ash_test/ash-vars/unset.tests
@@ -0,0 +1,40 @@
+# check invalid options are rejected
+# bash: in posix mode, aborts if non-interactive; using subshell to avoid that
+(unset -)
+echo $?
+(unset -m a b c)
+echo $?
+
+# check funky usage
+unset
+echo $?
+
+# check normal usage
+echo ___
+f=f g=g
+echo $? $f $g
+unset f
+echo $? $f $g
+unset g
+echo $? $f $g
+
+echo ___
+f=f g=g
+echo $? $f $g
+unset f g
+echo $? $f $g
+f=f g=g
+echo $? $f $g
+unset -v f g
+echo $? $f $g
+
+# check read only vars
+echo ___
+f=f g=g
+VAR_RO=1
+readonly VAR_RO
+(unset VAR_RO)
+echo $? $f $g
+# not testing "do variables survive error halfway through unset" since unset aborts
+# unset f VAR_RO g
+#echo $? $f $g
diff --git a/shell/hush_test/hush-vars/unset.right b/shell/hush_test/hush-vars/unset.right
index 1fbe76a..0972742 100644
--- a/shell/hush_test/hush-vars/unset.right
+++ b/shell/hush_test/hush-vars/unset.right
@@ -12,7 +12,7 @@
0 f g
0
___
-hush: HUSH_VERSION: readonly variable
+hush: VAR_RO: readonly variable
1 f g
-hush: HUSH_VERSION: readonly variable
+hush: VAR_RO: readonly variable
1
diff --git a/shell/hush_test/hush-vars/unset.tests b/shell/hush_test/hush-vars/unset.tests
index f59ce59..81243fb 100755
--- a/shell/hush_test/hush-vars/unset.tests
+++ b/shell/hush_test/hush-vars/unset.tests
@@ -1,4 +1,5 @@
# check invalid options are rejected
+# bash: in posix mode, aborts if non-interactive
unset -
echo $?
unset -m a b c
@@ -30,7 +31,9 @@
# check read only vars
echo ___
f=f g=g
-unset HUSH_VERSION
+VAR_RO=1
+readonly VAR_RO
+unset VAR_RO
echo $? $f $g
-unset f HUSH_VERSION g
+unset f VAR_RO g
echo $? $f $g