aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2010-07-06 17:40:53 +0800
committermaximilian attems <max@stro.at>2011-06-03 18:44:12 +0200
commite06c8619926ecfb590dfde71ecbb76abc0216fcb (patch)
tree1692fb1f732e0309277cfa2cba72153701772dbf
parentc2c398310975f491836eb01db26919f8ea7497e3 (diff)
downloadklibc-e06c8619926ecfb590dfde71ecbb76abc0216fcb.tar.gz
[klibc] [VAR] Fix loss of variables when hash collides
Brian Koropoff reported that the new var patches broke the following script: #!/bin/dash GDM_LANG="bar" OPTION="foo" unset GDM_LANG # OPTION has mysteriously become unset echo "$OPTION" He correctly diagnosed this as a result of removing all variables in the hash chain preceding the one that should be removed in setvareq. He also provided a patch to fix this. This patch is based on his but without keeping the original vpp. As a result, we now store new variables at the end of the hash chain instead of the beginning. To make this work, setvareq/setvar now returns the vp pointer modified. In case they're used to unset a variable the pointer returned is undefined. This is because mklocal needs it and used to get it by assuming that the new variable always appear at the beginning of the chain. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: maximilian attems <max@stro.at>
-rw-r--r--usr/dash/var.c28
-rw-r--r--usr/dash/var.h4
2 files changed, 18 insertions, 14 deletions
diff --git a/usr/dash/var.c b/usr/dash/var.c
index f456fbdd14f54..3efc943217947 100644
--- a/usr/dash/var.c
+++ b/usr/dash/var.c
@@ -180,13 +180,13 @@ initvar(void)
* flags of the variable. If val is NULL, the variable is unset.
*/
-void
-setvar(const char *name, const char *val, int flags)
+struct var *setvar(const char *name, const char *val, int flags)
{
char *p, *q;
size_t namelen;
char *nameeq;
size_t vallen;
+ struct var *vp;
q = endofname(name);
p = strchrnul(q, '=');
@@ -206,8 +206,10 @@ setvar(const char *name, const char *val, int flags)
p = mempcpy(p, val, vallen);
}
*p = '\0';
- setvareq(nameeq, flags | VNOSAVE);
+ vp = setvareq(nameeq, flags | VNOSAVE);
INTON;
+
+ return vp;
}
/*
@@ -235,14 +237,14 @@ intmax_t setvarint(const char *name, intmax_t val, int flags)
* Called with interrupts off.
*/
-void
-setvareq(char *s, int flags)
+struct var *setvareq(char *s, int flags)
{
struct var *vp, **vpp;
vpp = hashvar(s);
flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
- vp = *findvar(vpp, s);
+ vpp = findvar(vpp, s);
+ vp = *vpp;
if (vp) {
if (vp->flags & VREADONLY) {
const char *n;
@@ -255,7 +257,7 @@ setvareq(char *s, int flags)
}
if (flags & VNOSET)
- return;
+ goto out;
if (vp->func && (flags & VNOFUNC) == 0)
(*vp->func)(strchrnul(s, '=') + 1);
@@ -270,13 +272,13 @@ setvareq(char *s, int flags)
out_free:
if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
ckfree(s);
- return;
+ goto out;
}
flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
} else {
if (flags & VNOSET)
- return;
+ goto out;
if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
goto out_free;
/* not found */
@@ -289,6 +291,9 @@ out_free:
s = savestr(s);
vp->text = s;
vp->flags = flags;
+
+out:
+ return vp;
}
@@ -486,10 +491,9 @@ void mklocal(char *name)
eq = strchr(name, '=');
if (vp == NULL) {
if (eq)
- setvareq(name, VSTRFIXED);
+ vp = setvareq(name, VSTRFIXED);
else
- setvar(name, NULL, VSTRFIXED);
- vp = *vpp; /* the new variable */
+ vp = setvar(name, NULL, VSTRFIXED);
lvp->flags = VUNSET;
} else {
lvp->text = vp->text;
diff --git a/usr/dash/var.h b/usr/dash/var.h
index 097b2550184a1..afdd0f6ade478 100644
--- a/usr/dash/var.h
+++ b/usr/dash/var.h
@@ -128,9 +128,9 @@ extern const char defpathvar[];
#define mpathset() ((vmpath.flags & VUNSET) == 0)
void initvar(void);
-void setvar(const char *, const char *, int);
+struct var *setvar(const char *name, const char *val, int flags);
intmax_t setvarint(const char *, intmax_t, int);
-void setvareq(char *, int);
+struct var *setvareq(char *s, int flags);
struct strlist;
void listsetvar(struct strlist *, int);
char *lookupvar(const char *);