Date: Sat, 28 Apr 2018 03:53:12 +0200 From: Martijn Dekker <mart...@inlv.org> Message-ID: <81b93245-e42f-ad62-4005-8ad676733...@inlv.org>
| How does NetBSD sh handle this? This isn't really the best place for code samples, but ... "fd" is the file descriptor in question: if ((flags & REDIR_PUSH) && !is_renamed(sv->renamed, fd)) { INTOFF; 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: i = errno; INTON; /* XXX not needed here ? */ error("%d: %s", fd, strerror(i)); /* NOTREACHED */ } } if (i >= 0) (void)fcntl(i, F_SETFD, FD_CLOEXEC); fd_rename(sv, fd, i); CLOSED is < 0 fd_rename() does (aside from bookkeeping) rl->orig = from; rl->into = to; The "sv" arg is the data struct where all this is saved (rl is alloc'd memory, linked to it). and then later, when things are being restored if (rl->into < 0) close(rl->orig); else movefd(rl->into, rl->orig); movefd() ends up translating into dup2() with error, and close-on-exec handling. The FreeBSD sh is similar, but simpler - they don't deal with user fd's >= 10, which makes the data structs needed simpler, and much easier to avoid user fd's stepping all over the shell's internal fds - we allow user fds to be anything the system allows, and the shell makes sure it moves its own fds around if needed to avoid issues. The EINVAL and EMFILE handling is dealing with the consequences of the user/script playing with ulimit, or at least as much as is possible. | If it's a bug, surely it would meet that requirement. Not for me to say, but it it doesn't have to be different (rather than just would be nicer if it was different) then it can be hard to justify making changes. kre