aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2010-05-27 15:03:46 +0800
committermaximilian attems <max@stro.at>2011-06-03 18:44:12 +0200
commit69b47734e1b758315cddac7e2e37c72b3b59f178 (patch)
tree64f14702b7e5dacaf6d7deb0c614e9152bdc2e1a
parent22319814b9556654e20bf1a6af7bb435e37f3aeb (diff)
downloadklibc-69b47734e1b758315cddac7e2e37c72b3b59f178.tar.gz
[klibc] [REDIR] Fix popredir on abnormal exit from built-in
Just like the poplocalvar problem recently fixed, redirections can also be leaked in case of an abnormal exit. This patch fixes it using the same method as poplocalvar, by storing the previous redirection state and restoring to that point. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: maximilian attems <max@stro.at>
-rw-r--r--usr/dash/eval.c4
-rw-r--r--usr/dash/redir.c45
-rw-r--r--usr/dash/redir.h4
3 files changed, 40 insertions, 13 deletions
diff --git a/usr/dash/eval.c b/usr/dash/eval.c
index f73e6e987eedc..3cd2c5f9d90f7 100644
--- a/usr/dash/eval.c
+++ b/usr/dash/eval.c
@@ -219,6 +219,7 @@ evaltree(union node *n, int flags)
goto setstatus;
case NREDIR:
expredir(n->nredir.redirect);
+ pushredir(n->nredir.redirect);
status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
if (!status) {
evaltree(n->nredir.n, flags & EV_TESTED);
@@ -683,6 +684,7 @@ evalcommand(union node *cmd, int flags)
#endif
{
struct localvar_list *localvar_stop;
+ struct redirtab *redir_stop;
struct stackmark smark;
union node *argp;
struct arglist arglist;
@@ -740,6 +742,7 @@ evalcommand(union node *cmd, int flags)
preverrout.fd = 2;
expredir(cmd->ncmd.redirect);
+ redir_stop = pushredir(cmd->ncmd.redirect);
status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
path = vpath.text;
@@ -882,6 +885,7 @@ raise:
out:
if (cmd->ncmd.redirect)
popredir(execcmd);
+ unwindredir(redir_stop);
unwindlocalvars(localvar_stop);
if (lastarg)
/* dsl: I think this is intended to be used to support
diff --git a/usr/dash/redir.c b/usr/dash/redir.c
index 16decfc968d36..b4e49c0ebcacf 100644
--- a/usr/dash/redir.c
+++ b/usr/dash/redir.c
@@ -111,20 +111,12 @@ redirect(union node *redir, int flags)
memory[i] = 0;
memory[1] = flags & REDIR_BACKQ;
#endif
- if (!redir) {
+ if (!redir)
return;
- }
sv = NULL;
INTOFF;
- if (likely(flags & REDIR_PUSH)) {
- struct redirtab *q;
- q = ckmalloc(sizeof (struct redirtab));
- q->next = redirlist;
- redirlist = q;
- for (i = 0 ; i < 10 ; i++)
- q->renamed[i] = EMPTY;
- sv = q;
- }
+ if (likely(flags & REDIR_PUSH))
+ sv = redirlist;
n = redir;
do {
newfd = openredirect(n);
@@ -373,8 +365,7 @@ RESET {
/*
* Discard all saved file descriptors.
*/
- while (redirlist)
- popredir(0);
+ unwindredir(0);
}
#endif
@@ -485,3 +476,31 @@ redirectsafe(union node *redir, int flags)
RESTOREINT(saveint);
return err;
}
+
+
+void unwindredir(struct redirtab *stop)
+{
+ while (redirlist != stop)
+ popredir(0);
+}
+
+
+struct redirtab *pushredir(union node *redir)
+{
+ struct redirtab *sv;
+ struct redirtab *q;
+ int i;
+
+ q = redirlist;
+ if (!redir)
+ goto out;
+
+ sv = ckmalloc(sizeof (struct redirtab));
+ sv->next = q;
+ redirlist = sv;
+ for (i = 0; i < 10; i++)
+ sv->renamed[i] = EMPTY;
+
+out:
+ return q;
+}
diff --git a/usr/dash/redir.h b/usr/dash/redir.h
index ab7ebba0662af..8e56995f04e10 100644
--- a/usr/dash/redir.h
+++ b/usr/dash/redir.h
@@ -41,9 +41,13 @@
#endif
#define REDIR_SAVEFD2 03 /* set preverrout */
+struct redirtab;
union node;
void redirect(union node *, int);
void popredir(int);
void clearredir(void);
int savefd(int, int);
int redirectsafe(union node *, int);
+void unwindredir(struct redirtab *stop);
+struct redirtab *pushredir(union node *redir);
+