From 9439b981d816a25883bd9d8f05af62664f21e0bc Mon Sep 17 00:00:00 2001 From: ksss Date: Thu, 4 Dec 2014 09:05:24 +0900 Subject: Opened fd should be set FD_CLOEXEC by default --- src/io.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/io.c b/src/io.c index d7e1b0fba..560fba3de 100644 --- a/src/io.c +++ b/src/io.c @@ -125,6 +125,30 @@ mrb_io_flags_to_modenum(mrb_state *mrb, int flags) return modenum; } +void +mrb_fd_cloexec(mrb_state *mrb, int fd) +{ + int flags, flags2; + +#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) + flags = fcntl(fd, F_GETFD); + if (flags == -1) { + mrb_sys_fail(mrb, "fcntl"); + } + if (fd <= 2) { + flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */ + } + else { + flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */ + } + if (flags != flags2) { + if (fcntl(fd, F_SETFD, flags2) == -1) { + mrb_sys_fail(mrb, "fcntl"); + } + } +#endif +} + #ifndef _WIN32 static int mrb_proc_exec(const char *pname) @@ -367,6 +391,38 @@ mrb_io_s_sysclose(mrb_state *mrb, mrb_value klass) return mrb_fixnum_value(0); } +int +mrb_cloexec_open(mrb_state *mrb, const char *pathname, mrb_int flags, mrb_int mode) +{ + int fd, retry = FALSE; + +#ifdef O_CLOEXEC + /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */ + flags |= O_CLOEXEC; +#elif defined O_NOINHERIT + flags |= O_NOINHERIT; +#endif +reopen: + fd = open(pathname, flags, mode); + if (fd == -1) { + if (!retry) { + switch (errno) { + case ENFILE: + case EMFILE: + mrb_garbage_collect(mrb); + retry = TRUE; + goto reopen; + } + } + mrb_sys_fail(mrb, "open"); + } + + if (fd <= 2) { + mrb_fd_cloexec(mrb, fd); + } + return fd; +} + mrb_value mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) { @@ -374,7 +430,7 @@ mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) mrb_value mode = mrb_nil_value(); mrb_int fd, flags, perm = -1; const char *pat; - int modenum, retry = FALSE; + int modenum; mrb_get_args(mrb, "S|Si", &path, &mode, &perm); if (mrb_nil_p(mode)) { @@ -387,22 +443,7 @@ mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) pat = mrb_string_value_cstr(mrb, &path); flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); modenum = mrb_io_flags_to_modenum(mrb, flags); - - reopen: - fd = open(pat, modenum, perm); - if (fd == -1) { - if (!retry) { - switch (errno) { - case ENFILE: - case EMFILE: - mrb_garbage_collect(mrb); - retry = TRUE; - goto reopen; - } - } - mrb_sys_fail(mrb, pat); - } - + fd = mrb_cloexec_open(mrb, pat, modenum, perm); return mrb_fixnum_value(fd); } @@ -745,7 +786,7 @@ mrb_io_close_on_exec_p(mrb_state *mrb, mrb_value io) #if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC) struct mrb_io *fptr; int ret; - + fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); if (fptr->fd < 0) { mrb_raise(mrb, E_IO_ERROR, "closed stream"); @@ -787,7 +828,7 @@ mrb_io_set_close_on_exec(mrb_state *mrb, mrb_value io) if ((ret & FD_CLOEXEC) != flag) { ret = (ret & ~FD_CLOEXEC) | flag; ret = fcntl(fptr->fd2, F_SETFD, ret); - + if (ret == -1) mrb_sys_fail(mrb, "F_SETFD failed"); } } -- cgit v1.2.3 From e61c46972482ca2b4e9b338f9ccfa4ee13efa62d Mon Sep 17 00:00:00 2001 From: ksss Date: Thu, 4 Dec 2014 10:21:29 +0900 Subject: IO.popen fd set close_on_exec flag by default --- src/io.c | 21 +++++++++++++++------ test/io.rb | 1 + 2 files changed, 16 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/io.c b/src/io.c index 560fba3de..3f299775e 100644 --- a/src/io.c +++ b/src/io.c @@ -223,13 +223,22 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) doexec = (strcmp("-", pname) != 0); - if ((flags & FMODE_READABLE) && pipe(pr) == -1) { - mrb_sys_fail(mrb, "pipe"); + if (flags & FMODE_READABLE) { + if (pipe(pr) == -1) { + mrb_sys_fail(mrb, "pipe"); + } + mrb_fd_cloexec(mrb, pr[0]); + mrb_fd_cloexec(mrb, pr[1]); } - if ((flags & FMODE_WRITABLE) && pipe(pw) == -1) { - if (pr[0] != -1) close(pr[0]); - if (pr[1] != -1) close(pr[1]); - mrb_sys_fail(mrb, "pipe"); + + if (flags & FMODE_WRITABLE) { + if (pipe(pw) == -1) { + if (pr[0] != -1) close(pr[0]); + if (pr[1] != -1) close(pr[1]); + mrb_sys_fail(mrb, "pipe"); + } + mrb_fd_cloexec(mrb, pw[0]); + mrb_fd_cloexec(mrb, pw[1]); } if (!doexec) { diff --git a/test/io.rb b/test/io.rb index 9c7ce741f..b828fef49 100644 --- a/test/io.rb +++ b/test/io.rb @@ -321,6 +321,7 @@ end assert('IO.popen') do io = IO.popen("ls") + assert_true io.close_on_exec? assert_equal Fixnum, io.pid.class ls = io.read assert_equal ls.class, String -- cgit v1.2.3