summaryrefslogtreecommitdiff
path: root/io.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-04-24 14:46:39 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-04-24 14:46:39 +0000
commit278b63a3e459993c44aa0515239970fde517642a (patch)
treee529cfce435bff40c710dec4f838b3e861a3fd0d /io.c
parent9b694aaa8588a1f43fd0ae8c1142c7a854a3f6c6 (diff)
* include/ruby/intern.h (rb_env_clear): declared.
(rb_io_mode_modenum): declared. (rb_close_before_exec): declared. (struct rb_exec_arg): add options and redirect_fds field. (rb_check_argv): removed. (rb_exec_initarg): declared. (rb_exec_getargs): declared. (rb_exec_initarg2): declared. (rb_fork): add third argument: fds. * io.c (max_file_descriptor): new static variable to record maximum file descriptor ruby used. (UPDATE_MAXFD): new macro. (UPDATE_MAXFD_PIPE): new macro. (rb_io_mode_modenum): externed. (rb_sysopen): update max_file_descriptor. (rb_close_before_exec): new function. (popen_exec): redirection removed because it is done by extended spawn mechanism. (pipe_open): generate a hash for spawn options to specify redirections. (pipe_open_v): use rb_exec_getargs. (pipe_open_s): use rb_exec_getargs. (rb_io_initialize): update max_file_descriptor.. * process.c (hide_obj): new function. (check_exec_redirect_fd): new function. (check_exec_redirect): new function. (check_exec_options_i): new function. (check_exec_fds): new function. (rb_check_exec_options): new function. (check_exec_env_i): new function. (rb_check_exec_env): new function. (rb_exec_getargs): new function. (rb_exec_initarg2): new function. (rb_exec_initarg): new function. (rb_f_exec): use rb_exec_initarg. (intcmp): new function. (run_exec_dup2): new function. (run_exec_close): new function. (run_exec_open): new function. (run_exec_pgroup): new function. (run_exec_rlimit): new function. (run_exec_options): new function. (rb_exec): call run_exec_options. (move_fds_to_avoid_crash): new function. (pipe_nocrash): new function. (rb_fork): use pipe_nocrash to avoid file descriptor conflicts. (rb_spawn): use rb_exec_initarg. (rlimit_resource_name2int): extracted from rlimit_resource_type. (rlimit_type_by_hname): new function. (rlimit_type_by_lname): new function. (rlimit_resource_type): use rlimit_type_by_hname. (proc_daemon): add fds argument for rb_fork. * hash.c (rb_env_clear): renamed from env_clear and externed. [ruby-dev:34086] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16183 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'io.c')
-rw-r--r--io.c116
1 files changed, 89 insertions, 27 deletions
diff --git a/io.c b/io.c
index d682ea288a..a4382445a0 100644
--- a/io.c
+++ b/io.c
@@ -139,6 +139,18 @@ struct argf {
rb_encoding *enc, *enc2;
};
+static int max_file_descriptor = NOFILE;
+#define UPDATE_MAXFD(fd) \
+ do { \
+ if (max_file_descriptor < (fd)) max_file_descriptor = (fd); \
+ } while (0)
+#define UPDATE_MAXFD_PIPE(filedes) \
+ do { \
+ UPDATE_MAXFD((filedes)[0]); \
+ UPDATE_MAXFD((filedes)[1]); \
+ } while (0)
+
+
#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
#define ARGF argf_of(argf)
@@ -3228,7 +3240,7 @@ rb_io_modenum_flags(int mode)
return flags;
}
-static int
+int
rb_io_mode_modenum(const char *mode)
{
int flags = 0;
@@ -3387,6 +3399,7 @@ rb_sysopen(char *fname, int flags, unsigned int mode)
rb_sys_fail(fname);
}
}
+ UPDATE_MAXFD(fd);
return fd;
}
@@ -3629,26 +3642,41 @@ popen_redirect(struct popen_arg *p)
}
}
+void
+rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
+{
+ int fd, ret;
+ int max = max_file_descriptor;
+ if (max < maxhint)
+ max = maxhint;
+ for (fd = lowfd; fd <= max; fd++) {
+ if (!NIL_P(noclose_fds) &&
+ RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd))))
+ continue;
+#ifdef FD_CLOEXEC
+ ret = fcntl(fd, F_GETFD);
+ if (ret != -1 && !(ret & FD_CLOEXEC)) {
+ fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
+ }
+#else
+ close(fd);
+#endif
+ }
+}
+
static int
popen_exec(void *pp)
{
struct popen_arg *p = (struct popen_arg*)pp;
- int fd;
rb_thread_atfork();
- popen_redirect(p);
- for (fd = 3; fd < NOFILE; fd++) {
-#ifdef FD_CLOEXEC
- if (fcntl(fd, F_GETFD) & FD_CLOEXEC) continue;
-#endif
- close(fd);
- }
return rb_exec(&p->exec);
}
#endif
static VALUE
-pipe_open(const char *cmd, int argc, VALUE *argv, const char *mode)
+pipe_open(VALUE prog, int argc, VALUE *argv,
+ VALUE env, VALUE opthash, const char *mode)
{
int modef = rb_io_mode_flags(mode);
int pid = 0;
@@ -3659,6 +3687,7 @@ pipe_open(const char *cmd, int argc, VALUE *argv, const char *mode)
#if defined(HAVE_FORK)
int status;
struct popen_arg arg;
+ VALUE env2 = 0;
#elif defined(_WIN32)
int openmode = rb_io_mode_modenum(mode);
const char *exename = NULL;
@@ -3667,8 +3696,16 @@ pipe_open(const char *cmd, int argc, VALUE *argv, const char *mode)
FILE *fp = 0;
int fd = -1;
int write_fd = -1;
+ const char *cmd = 0;
+
+ if (prog)
+ cmd = StringValueCStr(prog);
#if defined(HAVE_FORK)
+ if (prog) {
+ env2 = rb_hash_new();
+ RBASIC(env2)->klass = 0;
+ }
arg.modef = modef;
arg.pair[0] = arg.pair[1] = -1;
arg.write_pair[0] = arg.write_pair[1] = -1;
@@ -3676,6 +3713,7 @@ pipe_open(const char *cmd, int argc, VALUE *argv, const char *mode)
case FMODE_READABLE|FMODE_WRITABLE:
if (pipe(arg.write_pair) < 0)
rb_sys_fail(cmd);
+ UPDATE_MAXFD_PIPE(arg.write_pair);
if (pipe(arg.pair) < 0) {
int e = errno;
close(arg.write_pair[0]);
@@ -3683,29 +3721,47 @@ pipe_open(const char *cmd, int argc, VALUE *argv, const char *mode)
errno = e;
rb_sys_fail(cmd);
}
+ UPDATE_MAXFD_PIPE(arg.pair);
+ if (env2) {
+ rb_hash_aset(env2, INT2FIX(0), INT2FIX(arg.write_pair[0]));
+ rb_hash_aset(env2, INT2FIX(1), INT2FIX(arg.pair[1]));
+ }
break;
case FMODE_READABLE:
if (pipe(arg.pair) < 0)
rb_sys_fail(cmd);
+ UPDATE_MAXFD_PIPE(arg.pair);
+ if (env2)
+ rb_hash_aset(env2, INT2FIX(1), INT2FIX(arg.pair[1]));
break;
case FMODE_WRITABLE:
if (pipe(arg.pair) < 0)
rb_sys_fail(cmd);
+ UPDATE_MAXFD_PIPE(arg.pair);
+ if (env2)
+ rb_hash_aset(env2, INT2FIX(0), INT2FIX(arg.pair[0]));
break;
default:
rb_sys_fail(cmd);
}
- if (cmd) {
- arg.exec.argc = argc;
- arg.exec.argv = argv;
- arg.exec.prog = cmd;
- pid = rb_fork(&status, popen_exec, &arg);
+ if (prog) {
+ VALUE close_others = ID2SYM(rb_intern("close_others"));
+ if (NIL_P(opthash) || !st_lookup(RHASH_TBL(opthash), close_others, 0))
+ rb_hash_aset(env2, close_others, Qtrue);
+ if (NIL_P(opthash))
+ opthash = env2;
+ else {
+ opthash = rb_assoc_new(env2, opthash);
+ RBASIC(opthash)->klass = 0;
+ }
+ rb_exec_initarg2(prog, argc, argv, env, opthash, &arg.exec);
+ pid = rb_fork(&status, popen_exec, &arg, arg.exec.redirect_fds);
}
else {
fflush(stdin); /* is it really needed? */
rb_io_flush(rb_stdout);
rb_io_flush(rb_stderr);
- pid = rb_fork(&status, 0, 0);
+ pid = rb_fork(&status, 0, 0, Qnil);
if (pid == 0) { /* child */
popen_redirect(&arg);
rb_io_synchronized(RFILE(orig_stdout)->fptr);
@@ -3812,27 +3868,29 @@ pipe_open(const char *cmd, int argc, VALUE *argv, const char *mode)
static VALUE
pipe_open_v(int argc, VALUE *argv, const char *mode)
{
- VALUE prog = rb_check_argv(argc, argv);
- const char *cmd;
-
- if (!RB_GC_GUARD(prog)) prog = argv[0];
- cmd = StringValueCStr(prog);
- return pipe_open(cmd, argc, argv, mode);
+ VALUE prog, env=Qnil, opthash=Qnil;
+ prog = rb_exec_getargs(&argc, &argv, Qfalse, &env, &opthash);
+ return pipe_open(prog, argc, argv, env, opthash, mode);
}
static VALUE
pipe_open_s(VALUE prog, const char *mode)
{
- const char *cmd = (rb_check_argv(1, &prog), RSTRING_PTR(prog));
+ const char *cmd = RSTRING_PTR(prog);
+ int argc = 1;
+ VALUE *argv = &prog;
+ VALUE env=Qnil, opthash=Qnil;
- if (strcmp("-", cmd) == 0) {
+ if (RSTRING_LEN(prog) == 1 && cmd[0] == '-') {
#if !defined(HAVE_FORK)
rb_raise(rb_eNotImpError,
"fork() function is unimplemented on this machine");
#endif
- cmd = 0;
+ return pipe_open(0, 0, 0, Qnil, Qnil, mode);
}
- return pipe_open(cmd, 0, &prog, mode);
+
+ rb_exec_getargs(&argc, &argv, Qtrue, &env, &opthash);
+ return pipe_open(prog, 0, 0, Qnil, Qnil, mode);
}
/*
@@ -3845,7 +3903,9 @@ pipe_open_s(VALUE prog, const char *mode)
* <code>IO</code> object. If _cmd_ is a +String+
* ``<code>-</code>'', then a new instance of Ruby is started as the
* subprocess. If <i>cmd</i> is an +Array+ of +String+, then it will
- * be used as the subprocess's +argv+ bypassing a shell. The default
+ * be used as the subprocess's +argv+ bypassing a shell.
+ * The array can contains a hash at first for environments and
+ * a hash at last for options similar to <code>spawn</code>. The default
* mode for the new file object is ``r'', but <i>mode</i> may be set
* to any of the modes listed in the description for class IO.
*
@@ -4873,6 +4933,7 @@ rb_io_initialize(int argc, VALUE *argv, VALUE io)
orig = rb_io_check_io(fnum);
if (NIL_P(orig)) {
fd = NUM2INT(fnum);
+ UPDATE_MAXFD(fd);
if (argc != 2) {
#if defined(HAVE_FCNTL) && defined(F_GETFL)
flags = fcntl(fd, F_GETFL);
@@ -6021,6 +6082,7 @@ rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
rb_scan_args(argc, argv, "02", &v1, &v2);
if (pipe(pipes) == -1)
rb_sys_fail(0);
+ UPDATE_MAXFD_PIPE(pipes);
args[0] = klass;
args[1] = INT2NUM(pipes[0]);