Module Name:    src
Committed By:   christos
Date:           Mon May  2 01:46:31 UTC 2016

Modified Files:
        src/bin/sh: cd.c eval.c input.c jobs.c parser.c redir.c redir.h

Log Message:
Fix handing of user file descriptors outside the 0..9 range.
Also, move (most of) the shell's internal use fd's to much
higher values (depending upon what ulimit -n allows) so they
are less likely to clash with user supplied fd numbers.  A future
patch will (hopefully) avoid this problem completely by dynamically
moving the shell's internal fds around as needed. (From kre@)


To generate a diff of this commit:
cvs rdiff -u -r1.45 -r1.46 src/bin/sh/cd.c
cvs rdiff -u -r1.119 -r1.120 src/bin/sh/eval.c
cvs rdiff -u -r1.48 -r1.49 src/bin/sh/input.c
cvs rdiff -u -r1.75 -r1.76 src/bin/sh/jobs.c
cvs rdiff -u -r1.116 -r1.117 src/bin/sh/parser.c
cvs rdiff -u -r1.42 -r1.43 src/bin/sh/redir.c
cvs rdiff -u -r1.18 -r1.19 src/bin/sh/redir.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/bin/sh/cd.c
diff -u src/bin/sh/cd.c:1.45 src/bin/sh/cd.c:1.46
--- src/bin/sh/cd.c:1.45	Sun Jan  3 22:00:24 2016
+++ src/bin/sh/cd.c	Sun May  1 21:46:31 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: cd.c,v 1.45 2016/01/04 03:00:24 christos Exp $	*/
+/*	$NetBSD: cd.c,v 1.46 2016/05/02 01:46:31 christos Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)cd.c	8.2 (Berkeley) 5/4/95";
 #else
-__RCSID("$NetBSD: cd.c,v 1.45 2016/01/04 03:00:24 christos Exp $");
+__RCSID("$NetBSD: cd.c,v 1.46 2016/05/02 01:46:31 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -427,11 +427,7 @@ find_curdir(int noerror)
 		jp = makejob(NULL, 1);
 		if (forkshell(jp, NULL, FORK_NOJOB) == 0) {
 			(void) close(pip[0]);
-			if (pip[1] != 1) {
-				close(1);
-				copyfd(pip[1], 1, 1, 0);
-				close(pip[1]);
-			}
+			movefd(pip[1], 1);
 			(void) execl("/bin/pwd", "pwd", (char *)0);
 			error("Cannot exec /bin/pwd");
 		}

Index: src/bin/sh/eval.c
diff -u src/bin/sh/eval.c:1.119 src/bin/sh/eval.c:1.120
--- src/bin/sh/eval.c:1.119	Wed Mar 16 17:20:59 2016
+++ src/bin/sh/eval.c	Sun May  1 21:46:31 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: eval.c,v 1.119 2016/03/16 21:20:59 christos Exp $	*/
+/*	$NetBSD: eval.c,v 1.120 2016/05/02 01:46:31 christos Exp $	*/
 
 /*-
  * Copyright (c) 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)eval.c	8.9 (Berkeley) 6/8/95";
 #else
-__RCSID("$NetBSD: eval.c,v 1.119 2016/03/16 21:20:59 christos Exp $");
+__RCSID("$NetBSD: eval.c,v 1.120 2016/05/02 01:46:31 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -508,6 +508,7 @@ expredir(union node *n)
 
 	for (redir = n ; redir ; redir = redir->nfile.next) {
 		struct arglist fn;
+
 		fn.lastp = &fn.list;
 		switch (redir->type) {
 		case NFROMTO:
@@ -566,18 +567,11 @@ evalpipe(union node *n)
 		}
 		if (forkshell(jp, lp->n, n->npipe.backgnd ? FORK_BG : FORK_FG) == 0) {
 			INTON;
-			if (prevfd > 0) {
-				close(0);
-				copyfd(prevfd, 0, 1, 0);
-				close(prevfd);
-			}
+			if (prevfd > 0)
+				movefd(prevfd, 0);
 			if (pip[1] >= 0) {
 				close(pip[0]);
-				if (pip[1] != 1) {
-					close(1);
-					copyfd(pip[1], 1, 1, 0);
-					close(pip[1]);
-				}
+				movefd(pip[1], 1);
 			}
 			evaltree(lp->n, EV_EXIT);
 		}
@@ -638,11 +632,7 @@ evalbackcmd(union node *n, struct backcm
 		if (forkshell(jp, n, FORK_NOJOB) == 0) {
 			FORCEINTON;
 			close(pip[0]);
-			if (pip[1] != 1) {
-				close(1);
-				copyfd(pip[1], 1, 1, 0);
-				close(pip[1]);
-			}
+			movefd(pip[1], 1);
 			eflag = 0;
 			evaltree(n, EV_EXIT);
 			/* NOTREACHED */
@@ -970,11 +960,7 @@ normal_fork:
 				FORCEINTON;
 			}
 			close(pip[0]);
-			if (pip[1] != 1) {
-				close(1);
-				copyfd(pip[1], 1, 1, 0);
-				close(pip[1]);
-			}
+			movefd(pip[1], 1);
 		}
 		flags |= EV_EXIT;
 	}

Index: src/bin/sh/input.c
diff -u src/bin/sh/input.c:1.48 src/bin/sh/input.c:1.49
--- src/bin/sh/input.c:1.48	Sun Mar 27 10:34:46 2016
+++ src/bin/sh/input.c	Sun May  1 21:46:31 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: input.c,v 1.48 2016/03/27 14:34:46 christos Exp $	*/
+/*	$NetBSD: input.c,v 1.49 2016/05/02 01:46:31 christos Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)input.c	8.3 (Berkeley) 6/9/95";
 #else
-__RCSID("$NetBSD: input.c,v 1.48 2016/03/27 14:34:46 christos Exp $");
+__RCSID("$NetBSD: input.c,v 1.49 2016/05/02 01:46:31 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -411,14 +411,13 @@ setinputfile(const char *fname, int push
 			error("Cannot rewind the file %s", fname);
 	}
 
-	if (fd < 10) {
-		fd2 = copyfd(fd, 10, 0, 0);
-		close(fd);
-		if (fd2 < 0)
-			error("Out of file descriptors");
-		fd = fd2;
+	fd2 = to_upper_fd(fd);	/* closes fd, returns higher equiv */
+	if (fd2 == fd) {
+		(void) close(fd);
+		error("Out of file descriptors");
 	}
-	setinputfd(fd, push);
+
+	setinputfd(fd2, push);
 	INTON;
 }
 

Index: src/bin/sh/jobs.c
diff -u src/bin/sh/jobs.c:1.75 src/bin/sh/jobs.c:1.76
--- src/bin/sh/jobs.c:1.75	Sat Aug 22 08:12:47 2015
+++ src/bin/sh/jobs.c	Sun May  1 21:46:31 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: jobs.c,v 1.75 2015/08/22 12:12:47 christos Exp $	*/
+/*	$NetBSD: jobs.c,v 1.76 2016/05/02 01:46:31 christos Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)jobs.c	8.5 (Berkeley) 5/4/95";
 #else
-__RCSID("$NetBSD: jobs.c,v 1.75 2015/08/22 12:12:47 christos Exp $");
+__RCSID("$NetBSD: jobs.c,v 1.76 2016/05/02 01:46:31 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -161,15 +161,7 @@ setjobctl(int on)
 			if (i == 3)
 				goto out;
 		}
-		/* Move to a high fd */
-		for (i = 10; i > 2; i--) {
-			if ((err = fcntl(ttyfd, F_DUPFD, (1 << i) - 1)) != -1)
-				break;
-		}
-		if (err != -1) {
-			close(ttyfd);
-			ttyfd = err;
-		}
+		ttyfd = to_upper_fd(ttyfd);	/* Move to a high fd */
 #ifdef FIOCLEX
 		err = ioctl(ttyfd, FIOCLEX, 0);
 #elif FD_CLOEXEC

Index: src/bin/sh/parser.c
diff -u src/bin/sh/parser.c:1.116 src/bin/sh/parser.c:1.117
--- src/bin/sh/parser.c:1.116	Mon Apr  4 08:39:08 2016
+++ src/bin/sh/parser.c	Sun May  1 21:46:31 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: parser.c,v 1.116 2016/04/04 12:39:08 christos Exp $	*/
+/*	$NetBSD: parser.c,v 1.117 2016/05/02 01:46:31 christos Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)parser.c	8.7 (Berkeley) 5/16/95";
 #else
-__RCSID("$NetBSD: parser.c,v 1.116 2016/04/04 12:39:08 christos Exp $");
+__RCSID("$NetBSD: parser.c,v 1.117 2016/05/02 01:46:31 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -50,7 +50,6 @@ __RCSID("$NetBSD: parser.c,v 1.116 2016/
 #include "nodes.h"
 #include "expand.h"	/* defines rmescapes() */
 #include "eval.h"	/* defines commandname */
-#include "redir.h"	/* defines copyfd() */
 #include "syntax.h"
 #include "options.h"
 #include "input.h"

Index: src/bin/sh/redir.c
diff -u src/bin/sh/redir.c:1.42 src/bin/sh/redir.c:1.43
--- src/bin/sh/redir.c:1.42	Sat Mar 12 20:22:42 2016
+++ src/bin/sh/redir.c	Sun May  1 21:46:31 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: redir.c,v 1.42 2016/03/13 01:22:42 christos Exp $	*/
+/*	$NetBSD: redir.c,v 1.43 2016/05/02 01:46:31 christos Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)redir.c	8.2 (Berkeley) 5/4/95";
 #else
-__RCSID("$NetBSD: redir.c,v 1.42 2016/03/13 01:22:42 christos Exp $");
+__RCSID("$NetBSD: redir.c,v 1.43 2016/05/02 01:46:31 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -76,9 +76,16 @@ __RCSID("$NetBSD: redir.c,v 1.42 2016/03
 
 
 MKINIT
+struct renamelist {
+	struct renamelist *next;
+	int orig;
+	int into;
+};
+
+MKINIT
 struct redirtab {
 	struct redirtab *next;
-	short renamed[10];
+	struct renamelist *renamed;
 };
 
 
@@ -88,12 +95,64 @@ MKINIT struct redirtab *redirlist;
  * We keep track of whether or not fd0 has been redirected.  This is for
  * background commands, where we want to redirect fd0 to /dev/null only
  * if it hasn't already been redirected.
-*/
-int fd0_redirected = 0;
+ */
+STATIC int fd0_redirected = 0;
 
+/*
+ * And also where to put internal use fds that should be out of the
+ * way of user defined fds (normally)
+ */
+STATIC int big_sh_fd = 0;
+
+STATIC const struct renamelist *is_renamed(const struct renamelist *, int);
+STATIC void fd_rename(struct redirtab *, int, int);
+STATIC void free_rl(struct redirtab *, int);
 STATIC void openredirect(union node *, char[10], int);
 STATIC int openhere(const union node *);
+STATIC void find_big_fd(void);
+
+STATIC const struct renamelist *
+is_renamed(const struct renamelist *rl, int fd)
+{
+	while (rl != NULL) {
+		if (rl->orig == fd)
+			return rl;
+		rl = rl->next;
+	}
+	return NULL;
+}
+
+STATIC void
+free_rl(struct redirtab *rt, int reset)
+{
+	struct renamelist *rl, *rn = rt->renamed;
+
+	while ((rl = rn) != NULL) {
+		rn = rl->next;
+		if (rl->orig == 0)
+			fd0_redirected--;
+		if (reset) {
+			if (rl->into < 0)
+				close(rl->orig);
+			else
+				movefd(rl->into, rl->orig);
+		}
+		ckfree(rl);
+	}
+	rt->renamed = NULL;
+}
 
+STATIC void
+fd_rename(struct redirtab *rt, int from, int to)
+{
+	struct renamelist *rl = ckmalloc(sizeof(struct renamelist));
+
+	rl->next = rt->renamed;
+	rt->renamed = rl;
+
+	rl->orig = from;
+	rl->into = to;
+}
 
 /*
  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
@@ -120,32 +179,45 @@ redirect(union node *redir, int flags)
 		 * flags & REDIR_PUSH is never true if REDIR_VFORK is set.
 		 */
 		sv = ckmalloc(sizeof (struct redirtab));
-		for (i = 0 ; i < 10 ; i++)
-			sv->renamed[i] = EMPTY;
+		sv->renamed = NULL;
 		sv->next = redirlist;
 		redirlist = sv;
 	}
 	for (n = redir ; n ; n = n->nfile.next) {
 		fd = n->nfile.fd;
 		if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
-		    n->ndup.dupfd == fd)
-			continue; /* redirect from/to same file descriptor */
+		    n->ndup.dupfd == fd) {
+			/* redirect from/to same file descriptor */
+			fcntl(fd, F_SETFD, 0);	/* make sure it stays open */
+			continue;
+		}
 
-		if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
+		if ((flags & REDIR_PUSH) && !is_renamed(sv->renamed, fd)) {
 			INTOFF;
-			if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
+			if (big_sh_fd < 10)
+				find_big_fd();
+			if ((i = fcntl(fd, F_DUPFD, big_sh_fd)) == -1) {
 				switch (errno) {
 				case EBADF:
 					i = CLOSED;
 					break;
+				case EMFILE:
+				case EINVAL:
+					find_big_fd();
+					i = fcntl(fd, F_DUPFD, big_sh_fd);
+					if (i >= 0)
+						break;
+					/* FALLTHRU */
 				default:
-					INTON;
-					error("%d: %s", fd, strerror(errno));
+					i = errno;
+					INTON;    /* XXX not needed here ? */
+					error("%d: %s", fd, strerror(i));
 					/* NOTREACHED */
 				}
-			} else
+			}
+			if (i >= 0)
 				(void)fcntl(i, F_SETFD, FD_CLOEXEC);
-			sv->renamed[fd] = i;
+			fd_rename(sv, fd, i);
 			INTON;
 		} else {
 			close(fd);
@@ -176,7 +248,8 @@ openredirect(union node *redir, char mem
 	 * an open of a device or a fifo can block indefinitely.
 	 */
 	INTOFF;
-	memory[fd] = 0;
+	if (fd < 10)
+		memory[fd] = 0;
 	switch (redir->nfile.type) {
 	case NFROM:
 		fname = redir->nfile.expfname;
@@ -227,7 +300,8 @@ openredirect(union node *redir, char mem
 	case NTOFD:
 	case NFROMFD:
 		if (redir->ndup.dupfd >= 0) {	/* if not ">&-" */
-			if (memory[redir->ndup.dupfd])
+			if (fd < 10 && redir->ndup.dupfd < 10 &&
+			    memory[redir->ndup.dupfd])
 				memory[fd] = 1;
 			else
 				copyfd(redir->ndup.dupfd, fd, 1,
@@ -312,20 +386,9 @@ void
 popredir(void)
 {
 	struct redirtab *rp = redirlist;
-	int i;
 
-	for (i = 0 ; i < 10 ; i++) {
-		if (rp->renamed[i] != EMPTY) {
-                        if (i == 0)
-                                fd0_redirected--;
-			close(i);
-			if (rp->renamed[i] >= 0) {
-				copyfd(rp->renamed[i], i, 1, 0);
-				close(rp->renamed[i]);
-			}
-		}
-	}
 	INTOFF;
+	free_rl(rp, 1);
 	redirlist = rp->next;
 	ckfree(rp);
 	INTON;
@@ -352,7 +415,8 @@ SHELLPROC {
 
 /* Return true if fd 0 has already been redirected at least once.  */
 int
-fd0_redirected_p (void) {
+fd0_redirected_p(void)
+{
         return fd0_redirected != 0;
 }
 
@@ -364,16 +428,14 @@ void
 clearredir(int vforked)
 {
 	struct redirtab *rp;
-	int i;
+	struct renamelist *rl;
 
 	for (rp = redirlist ; rp ; rp = rp->next) {
-		for (i = 0 ; i < 10 ; i++) {
-			if (rp->renamed[i] >= 0) {
-				close(rp->renamed[i]);
-			}
-			if (!vforked)
-				rp->renamed[i] = EMPTY;
-		}
+		if (!vforked)
+			free_rl(rp, 0);
+		else for (rl = rp->renamed; rl; rl = rl->next)
+			if (rl->into >= 0)
+				close(rl->into);
 	}
 }
 
@@ -409,3 +471,60 @@ copyfd(int from, int to, int equal, int 
 	}
 	return newfd;
 }
+
+int
+movefd(int from, int to)
+{
+	if (from == to)
+		return to;
+
+	(void) close(to);
+	if (copyfd(from, to, 1, 0) != to)
+		error("Unable to make fd %d", to);
+	(void) close(from);
+
+	return to;
+}
+
+STATIC void
+find_big_fd(void)
+{
+	int i, fd;
+
+	for (i = (1 << 10); i >= 10; i >>= 1) {
+		if ((fd = fcntl(0, F_DUPFD, i - 1)) >= 0) {
+			close(fd);
+			break;
+		}
+	}
+
+	fd = (i / 5) * 4;
+	if ((i - fd) > 100)
+		fd = i - 100;
+	else if (fd < 10)
+		fd = 10;
+
+	big_sh_fd = fd;
+}
+
+int
+to_upper_fd(int fd)
+{
+	int i;
+
+	if (big_sh_fd < 10)
+		find_big_fd();
+	do {
+		i = fcntl(fd, F_DUPFD, big_sh_fd);
+		if (i >= 0) {
+			if (fd != i)
+				close(fd);
+			return i;
+		}
+		if (errno != EMFILE)
+			break;
+		find_big_fd();
+	} while (big_sh_fd > 10);
+
+	return fd;
+}

Index: src/bin/sh/redir.h
diff -u src/bin/sh/redir.h:1.18 src/bin/sh/redir.h:1.19
--- src/bin/sh/redir.h:1.18	Sat Mar 12 16:35:13 2016
+++ src/bin/sh/redir.h	Sun May  1 21:46:31 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: redir.h,v 1.18 2016/03/12 21:35:13 christos Exp $	*/
+/*	$NetBSD: redir.h,v 1.19 2016/05/02 01:46:31 christos Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -46,4 +46,7 @@ void popredir(void);
 int fd0_redirected_p(void);
 void clearredir(int);
 int copyfd(int, int, int, int);
+int movefd(int, int);
+int to_upper_fd(int);
 
+extern int big_sh_fd;

Reply via email to