Date:        Fri, 29 Apr 2016 14:29:17 -0400
    From:        "Christos Zoulas" <chris...@netbsd.org>
    Message-ID:  <20160429182917.d265bf...@cvs.netbsd.org>

  | 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);

Reply via email to