Commit 6c4d3941 authored by Tomoyuki Sahara's avatar Tomoyuki Sahara

Merge pull request #30 from ksss/cloexec

Opened fd should be set FD_CLOEXEC by default
parents 042e4a43 e61c4697
...@@ -125,6 +125,30 @@ mrb_io_flags_to_modenum(mrb_state *mrb, int flags) ...@@ -125,6 +125,30 @@ mrb_io_flags_to_modenum(mrb_state *mrb, int flags)
return modenum; 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 #ifndef _WIN32
static int static int
mrb_proc_exec(const char *pname) mrb_proc_exec(const char *pname)
...@@ -199,13 +223,22 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) ...@@ -199,13 +223,22 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
doexec = (strcmp("-", pname) != 0); doexec = (strcmp("-", pname) != 0);
if ((flags & FMODE_READABLE) && pipe(pr) == -1) { if (flags & FMODE_READABLE) {
mrb_sys_fail(mrb, "pipe"); 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 (flags & FMODE_WRITABLE) {
if (pr[1] != -1) close(pr[1]); if (pipe(pw) == -1) {
mrb_sys_fail(mrb, "pipe"); 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) { if (!doexec) {
...@@ -389,6 +422,38 @@ mrb_io_s_sysclose(mrb_state *mrb, mrb_value klass) ...@@ -389,6 +422,38 @@ mrb_io_s_sysclose(mrb_state *mrb, mrb_value klass)
return mrb_fixnum_value(0); 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_value
mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass)
{ {
...@@ -396,7 +461,7 @@ 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_value mode = mrb_nil_value();
mrb_int fd, flags, perm = -1; mrb_int fd, flags, perm = -1;
const char *pat; const char *pat;
int modenum, retry = FALSE; int modenum;
mrb_get_args(mrb, "S|Si", &path, &mode, &perm); mrb_get_args(mrb, "S|Si", &path, &mode, &perm);
if (mrb_nil_p(mode)) { if (mrb_nil_p(mode)) {
...@@ -409,22 +474,7 @@ mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass) ...@@ -409,22 +474,7 @@ mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass)
pat = mrb_string_value_cstr(mrb, &path); pat = mrb_string_value_cstr(mrb, &path);
flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode));
modenum = mrb_io_flags_to_modenum(mrb, flags); modenum = mrb_io_flags_to_modenum(mrb, flags);
fd = mrb_cloexec_open(mrb, pat, modenum, perm);
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);
}
return mrb_fixnum_value(fd); return mrb_fixnum_value(fd);
} }
......
...@@ -321,6 +321,7 @@ end ...@@ -321,6 +321,7 @@ end
assert('IO.popen') do assert('IO.popen') do
io = IO.popen("ls") io = IO.popen("ls")
assert_true io.close_on_exec?
assert_equal Fixnum, io.pid.class assert_equal Fixnum, io.pid.class
ls = io.read ls = io.read
assert_equal ls.class, String assert_equal ls.class, String
...@@ -362,28 +363,28 @@ assert('IO#fileno') do ...@@ -362,28 +363,28 @@ assert('IO#fileno') do
io.closed? io.closed?
end end
assert('IO#close_on_exec') do assert('IO#close_on_exec') do
fd = IO.sysopen $mrbtest_io_wfname, "w" fd = IO.sysopen $mrbtest_io_wfname, "w"
io = IO.new fd, "w" io = IO.new fd, "w"
begin begin
# IO.sysopen opens a file descripter without O_CLOEXEC flag. # IO.sysopen opens a file descripter with O_CLOEXEC flag.
assert_equal(false, io.close_on_exec?) assert_true io.close_on_exec?
rescue ScriptError rescue ScriptError
skip "IO\#close_on_exec is not implemented." skip "IO\#close_on_exec is not implemented."
end end
io.close_on_exec = true
assert_equal(true, io.close_on_exec?)
io.close_on_exec = false io.close_on_exec = false
assert_equal(false, io.close_on_exec?) assert_equal(false, io.close_on_exec?)
io.close_on_exec = true io.close_on_exec = true
assert_equal(true, io.close_on_exec?) assert_equal(true, io.close_on_exec?)
io.close_on_exec = false
assert_equal(false, io.close_on_exec?)
io.close io.close
io.closed? io.closed?
# # Use below when IO.pipe is implemented. # # Use below when IO.pipe is implemented.
# begin # begin
# r, w = IO.pipe # r, w = IO.pipe
# assert_equal(false, r.close_on_exec?) # assert_equal(false, r.close_on_exec?)
# r.close_on_exec = true # r.close_on_exec = true
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment