diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/io.c | 96 |
1 files changed, 73 insertions, 23 deletions
@@ -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) @@ -199,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) { @@ -389,6 +422,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) { @@ -396,7 +461,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)) { @@ -409,22 +474,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); } |
