aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/ash.c58
1 files changed, 31 insertions, 27 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 647fc81b4..0490f7f7d 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -3760,12 +3760,12 @@ setjobctl(int on)
3760 if (--fd < 0) 3760 if (--fd < 0)
3761 goto out; 3761 goto out;
3762 } 3762 }
3763 /* fd is a tty at this point */
3763 fd = fcntl(fd, F_DUPFD, 10); 3764 fd = fcntl(fd, F_DUPFD, 10);
3764 if (ofd >= 0) 3765 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, dont */
3765 close(ofd); 3766 close(ofd);
3766 if (fd < 0) 3767 if (fd < 0)
3767 goto out; 3768 goto out; /* F_DUPFD failed */
3768 /* fd is a tty at this point */
3769 close_on_exec_on(fd); 3769 close_on_exec_on(fd);
3770 while (1) { /* while we are in the background */ 3770 while (1) { /* while we are in the background */
3771 pgrp = tcgetpgrp(fd); 3771 pgrp = tcgetpgrp(fd);
@@ -5181,26 +5181,31 @@ openredirect(union node *redir)
5181} 5181}
5182 5182
5183/* 5183/*
5184 * Copy a file descriptor to be >= to. Throws exception on error. 5184 * Copy a file descriptor to be >= 10. Throws exception on error.
5185 */ 5185 */
5186/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5187 * old code was doing close(to) prior to copyfd() to achieve the same */
5188enum {
5189 COPYFD_EXACT = (int)~(INT_MAX),
5190 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5191};
5192static int 5186static int
5193copyfd(int from, int to) 5187savefd(int from)
5194{ 5188{
5195 int newfd; 5189 int newfd;
5190 int err;
5196 5191
5197 if (to & COPYFD_EXACT) { 5192 newfd = fcntl(from, F_DUPFD, 10);
5198 to &= ~COPYFD_EXACT; 5193 err = newfd < 0 ? errno : 0;
5199 /*if (from != to)*/ 5194 if (err != EBADF) {
5200 newfd = dup2(from, to); 5195 if (err)
5201 } else { 5196 ash_msg_and_raise_error("%d: %m", from);
5202 newfd = fcntl(from, F_DUPFD, to); 5197 close(from);
5198 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5203 } 5199 }
5200
5201 return newfd;
5202}
5203static int
5204dup2_or_raise(int from, int to)
5205{
5206 int newfd;
5207
5208 newfd = (from != to) ? dup2(from, to) : to;
5204 if (newfd < 0) { 5209 if (newfd < 0) {
5205 /* Happens when source fd is not open: try "echo >&99" */ 5210 /* Happens when source fd is not open: try "echo >&99" */
5206 ash_msg_and_raise_error("%d: %m", from); 5211 ash_msg_and_raise_error("%d: %m", from);
@@ -5218,6 +5223,9 @@ struct redirtab {
5218 struct two_fd_t two_fd[]; 5223 struct two_fd_t two_fd[];
5219}; 5224};
5220#define redirlist (G_var.redirlist) 5225#define redirlist (G_var.redirlist)
5226enum {
5227 COPYFD_RESTORE = (int)~(INT_MAX),
5228};
5221 5229
5222static int 5230static int
5223need_to_remember(struct redirtab *rp, int fd) 5231need_to_remember(struct redirtab *rp, int fd)
@@ -5391,10 +5399,10 @@ redirect(union node *redir, int flags)
5391 if (fd != -1) 5399 if (fd != -1)
5392 close(fd); 5400 close(fd);
5393 } else { 5401 } else {
5394 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT); 5402 dup2_or_raise(redir->ndup.dupfd, fd);
5395 } 5403 }
5396 } else if (fd != newfd) { /* move newfd to fd */ 5404 } else if (fd != newfd) { /* move newfd to fd */
5397 copyfd(newfd, fd | COPYFD_EXACT); 5405 dup2_or_raise(newfd, fd);
5398#if ENABLE_ASH_BASH_COMPAT 5406#if ENABLE_ASH_BASH_COMPAT
5399 if (!(redir->nfile.type == NTO2 && fd == 2)) 5407 if (!(redir->nfile.type == NTO2 && fd == 2))
5400#endif 5408#endif
@@ -5440,7 +5448,7 @@ popredir(int drop, int restore)
5440 if (!drop || (restore && (copy & COPYFD_RESTORE))) { 5448 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
5441 copy &= ~COPYFD_RESTORE; 5449 copy &= ~COPYFD_RESTORE;
5442 /*close(fd);*/ 5450 /*close(fd);*/
5443 copyfd(copy, fd | COPYFD_EXACT); 5451 dup2_or_raise(copy, fd);
5444 } 5452 }
5445 close(copy & ~COPYFD_RESTORE); 5453 close(copy & ~COPYFD_RESTORE);
5446 } 5454 }
@@ -5894,7 +5902,7 @@ evalbackcmd(union node *n, struct backcmd *result)
5894 close(pip[0]); 5902 close(pip[0]);
5895 if (pip[1] != 1) { 5903 if (pip[1] != 1) {
5896 /*close(1);*/ 5904 /*close(1);*/
5897 copyfd(pip[1], 1 | COPYFD_EXACT); 5905 dup2_or_raise(pip[1], 1);
5898 close(pip[1]); 5906 close(pip[1]);
5899 } 5907 }
5900/* TODO: eflag clearing makes the following not abort: 5908/* TODO: eflag clearing makes the following not abort:
@@ -10204,7 +10212,6 @@ static int
10204setinputfile(const char *fname, int flags) 10212setinputfile(const char *fname, int flags)
10205{ 10213{
10206 int fd; 10214 int fd;
10207 int fd2;
10208 10215
10209 INT_OFF; 10216 INT_OFF;
10210 fd = open(fname, O_RDONLY); 10217 fd = open(fname, O_RDONLY);
@@ -10214,11 +10221,8 @@ setinputfile(const char *fname, int flags)
10214 exitstatus = 127; 10221 exitstatus = 127;
10215 ash_msg_and_raise_error("can't open '%s'", fname); 10222 ash_msg_and_raise_error("can't open '%s'", fname);
10216 } 10223 }
10217 if (fd < 10) { 10224 if (fd < 10)
10218 fd2 = copyfd(fd, 10); 10225 fd = savefd(fd);
10219 close(fd);
10220 fd = fd2;
10221 }
10222 setinputfd(fd, flags & INPUT_PUSH_FILE); 10226 setinputfd(fd, flags & INPUT_PUSH_FILE);
10223 out: 10227 out:
10224 INT_ON; 10228 INT_ON;