summary refs log tree commit diff
path: root/src/redir.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2010-05-27 15:03:46 +0800
committerHerbert Xu <herbert@gondor.apana.org.au>2010-05-27 15:03:46 +0800
commitb112dc08c6c86b8b82d60b1169ccab51921241ca (patch)
tree04bb75f4f823114f566d68ec52745421268baa99 /src/redir.c
parent[REDIR] Move null redirect checks into caller (diff)
downloaddash-b112dc08c6c86b8b82d60b1169ccab51921241ca.tar.gz
dash-b112dc08c6c86b8b82d60b1169ccab51921241ca.zip
[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>
Diffstat (limited to 'src/redir.c')
-rw-r--r--src/redir.c45
1 files changed, 32 insertions, 13 deletions
diff --git a/src/redir.c b/src/redir.c
index 16decfc..b4e49c0 100644
--- a/src/redir.c
+++ b/src/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;
+}