hush: do not assign to readonly VAR in "VAR=VAL CMD" syntax too
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 18 Jul 2017 00:44:06 +0000 (02:44 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 18 Jul 2017 00:44:06 +0000 (02:44 +0200)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/hush.c
shell/hush_test/hush-vars/readonly0.right
shell/hush_test/hush-vars/readonly0.tests

index eab1284f65d7b6f9ad2af8cdd89a853643350f06..55e581e16bf8c3bdc7fd046260a98cedf370d257 100644 (file)
@@ -2089,6 +2089,8 @@ static int set_local_var(char *str, unsigned flags)
                if (cur->flg_read_only) {
                        bb_error_msg("%s: readonly variable", str);
                        free(str);
+//NOTE: in bash, assignment in "export READONLY_VAR=Z" fails, and sets $?=1,
+//but export per se succeeds (does put the var in env). We don't mimic that.
                        return -1;
                }
                if (flags & SETFLAG_UNEXPORT) { // && cur->flg_export ?
@@ -2283,8 +2285,12 @@ static struct variable *set_vars_and_save_old(char **strings)
                if (eq) {
                        var_pp = get_ptr_to_local_var(*s, eq - *s);
                        if (var_pp) {
-                               /* Remove variable from global linked list */
                                var_p = *var_pp;
+                               if (var_p->flg_read_only) {
+                                       bb_error_msg("%s: readonly variable", *s);
+                                       goto next;
+                               }
+                               /* Remove variable from global linked list */
                                debug_printf_env("%s: removing '%s'\n", __func__, var_p->varstr);
                                *var_pp = var_p->next;
                                /* Add it to returned list */
@@ -2293,6 +2299,7 @@ static struct variable *set_vars_and_save_old(char **strings)
                        }
                        set_local_var(*s, SETFLAG_EXPORT);
                }
+ next:
                s++;
        }
        return old;
index 9688d2e5f1d1aa5974443fa2ac9936b259ee9fa8..07ca6e07f3f917147a0394ca978b2abde7aa110c 100644 (file)
@@ -5,8 +5,10 @@ hush: a=A: readonly variable
 Fail:1
 hush: a=A: readonly variable
 Fail:1
-hush: a=A: readonly variable
+hush: a=Z: readonly variable
 Fail:1
-Visible:0
+hush: a=Z: readonly variable
+b=B
+^^^a is not exported
 hush: a: readonly variable
 Fail:1
index 3845f76acb1629ef909e5782d7d14dfa5e03e5aa..3ace9b767ed5349906a7f286a9c344fa46faa894 100755 (executable)
@@ -1,10 +1,12 @@
+unset a b
+
 readonly a=A
 b=B
 readonly b
-# readonly on already readonly var is harmless
+# readonly on already readonly var is harmless:
 readonly b a
 readonly | grep '^readonly [ab]='
-# this should work
+# this should work:
 export a b
 export -n a b
 echo Ok:$?
@@ -12,13 +14,23 @@ env | grep -e^a= -e^b=  # shows nothing
 
 # these should all fail (despite the same value being assigned)
 # bash does not abort even in non-interactive more (in script)
-true
-a=A
-echo Fail:$?; true
-readonly a=A
-echo Fail:$?; true
-export a=A
+true; a=A
+echo Fail:$?
+true; readonly a=A
+echo Fail:$?
+
+# in bash, assignment in export fails, but export succeeds! :)
+# we don't mimic that!
+true; export a=Z
 echo Fail:$?; true
-a=A echo Visible:$? # command still runs
+#env | grep '^a='
+#echo "^^^a is exported"
+export -n a  # undo that bashism, if it happens
+
+export b
+# this fails to both set and export a:
+a=Z env | grep '^[ab]='  # command still runs
+echo "^^^a is not exported"
+
 unset a
 echo Fail:$?; true