Date: Fri, 29 Apr 2016 14:29:17 -0400 From: "Christos Zoulas" <christos%netbsd.org@localhost> Message-ID: <20160429182917.D265BFBBA%cvs.NetBSD.org@localhost> | use "" so ${TEST_SH} is expanded. Ugh!!! It worked for me as I always have TEST_SH in the environment, so it was getting expanded (much much) later... I'm appending a new version of the fd patch - the basics of it are all more or less unchanged, but the salad dressing has altered a bit. This applies to the CVS version of src/bin/sh - ignoring the previous patch. The system re-build finished (more or less, I forgot to fetch my src sets making script, which is a little different than the standard one, so no src sets got built) - aside from that, no problems. That was with the previous patch, I'm not sure if I will run it again (it took 18 1/2 hrs...) Sometime later I will also have a patch so that compiling with -DSTATIC=static works (which it definitely doesn't as it is.) I have been working on t_redir.sh so I'll append that as I have it at the minute (it passes with the shell with the patch included here) but there's still one empty test I want to finish before any of this is ready to commit. kre
Attachment:
T_REDIR.SH
Description: t_redir.sh
Index: cd.c =================================================================== RCS file: /cvsroot/src/bin/sh/cd.c,v retrieving revision 1.45 diff -u -u -r1.45 cd.c --- cd.c 4 Jan 2016 03:00:24 -0000 1.45 +++ cd.c 29 Apr 2016 20:16:39 -0000 @@ -427,11 +427,7 @@ 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: eval.c =================================================================== RCS file: /cvsroot/src/bin/sh/eval.c,v retrieving revision 1.119 diff -u -u -r1.119 eval.c --- eval.c 16 Mar 2016 21:20:59 -0000 1.119 +++ eval.c 29 Apr 2016 20:16:39 -0000 @@ -508,6 +508,7 @@ for (redir = n ; redir ; redir = redir->nfile.next) { struct arglist fn; + fn.lastp = &fn.list; switch (redir->type) { case NFROMTO: @@ -566,18 +567,11 @@ } 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 @@ 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 @@ 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: input.c =================================================================== RCS file: /cvsroot/src/bin/sh/input.c,v retrieving revision 1.48 diff -u -u -r1.48 input.c --- input.c 27 Mar 2016 14:34:46 -0000 1.48 +++ input.c 29 Apr 2016 20:16:39 -0000 @@ -411,14 +411,13 @@ 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: jobs.c =================================================================== RCS file: /cvsroot/src/bin/sh/jobs.c,v retrieving revision 1.75 diff -u -u -r1.75 jobs.c --- jobs.c 22 Aug 2015 12:12:47 -0000 1.75 +++ jobs.c 29 Apr 2016 20:16:40 -0000 @@ -161,15 +161,7 @@ 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: parser.c =================================================================== RCS file: /cvsroot/src/bin/sh/parser.c,v retrieving revision 1.116 diff -u -u -r1.116 parser.c --- parser.c 4 Apr 2016 12:39:08 -0000 1.116 +++ parser.c 29 Apr 2016 20:16:41 -0000 @@ -50,7 +50,6 @@ #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: redir.c =================================================================== RCS file: /cvsroot/src/bin/sh/redir.c,v retrieving revision 1.42 diff -u -u -r1.42 redir.c --- redir.c 13 Mar 2016 01:22:42 -0000 1.42 +++ redir.c 29 Apr 2016 20:16:41 -0000 @@ -76,9 +76,16 @@ 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,61 @@ * 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 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 +176,45 @@ * 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 +245,8 @@ * 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 +297,8 @@ 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 +383,9 @@ 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 +412,8 @@ /* 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 +425,14 @@ 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 +468,60 @@ } 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() +{ + 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: redir.h =================================================================== RCS file: /cvsroot/src/bin/sh/redir.h,v retrieving revision 1.18 diff -u -u -r1.18 redir.h --- redir.h 12 Mar 2016 21:35:13 -0000 1.18 +++ redir.h 29 Apr 2016 20:16:41 -0000 @@ -46,4 +46,5 @@ int fd0_redirected_p(void); void clearredir(int); int copyfd(int, int, int, int); - +int movefd(int, int); +int to_upper_fd(int);