ash: [VAR] Move unsetvar functionality into setvareq
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 25 Jul 2017 14:29:36 +0000 (16:29 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 25 Jul 2017 14:29:36 +0000 (16:29 +0200)
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>
shell/ash.c
shell/ash_test/ash-vars/readonly0.right
shell/ash_test/ash-vars/unset.right [new file with mode: 0644]
shell/ash_test/ash-vars/unset.tests [new file with mode: 0755]
shell/hush_test/hush-vars/unset.right
shell/hush_test/hush-vars/unset.tests

index 0ae086e985a000152882d60629fc5e70ed8dd27f..72ceba7822d789fb65c7d1f819476a02f1175920 100644 (file)
@@ -2269,11 +2269,22 @@ setvareq(char *s, int flags)
                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 @@ setvar0(const char *name, const char *val)
 /*
  * 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 @@ unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
        char **ap;
        int i;
        int flag = 0;
-       int ret = 0;
 
        while ((i = nextopt("vf")) != 0) {
                flag = i;
@@ -13226,15 +13203,13 @@ unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
 
        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 = {
index f3a6bde9eb39fd2cf0deef4ed6143214f16ab525..ecc4054f8c101ffcea08246f02b77b8e97c48016 100644 (file)
@@ -10,4 +10,4 @@ Fail:2
 ./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 (file)
index 0000000..77d5abe
--- /dev/null
@@ -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 (executable)
index 0000000..11b3927
--- /dev/null
@@ -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
index 1fbe76a73468403db794267eec4678c9958062de..0972742018568bee5043ef68825e4b1adfe30b6f 100644 (file)
@@ -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
index f59ce59231265bc969965c63616f2c3db9f98ce0..81243fbf9450f75d09c64fa85fcfad7fa8c2ebf4 100755 (executable)
@@ -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 @@ echo $? $f $g
 # 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