From 9416fedc282b6bd96fe1f150833db3e365029767 Mon Sep 17 00:00:00 2001 From: usa Date: Mon, 12 May 2008 14:15:32 +0000 Subject: * process.c, include/ruby/intern.h (rb_run_exec_options): externed. * process.c (save_redirect_fd, save_env_i, save_env, run_exec_dup2, run_exec_open, run_exec_pgroup, run_exec_rlimit, rb_run_exec_options): save parent's process environments. !!!remark!!! these are not thread-safe. * process.c (rb_spawn_internal): remove calling run_exec_options() because cannot restore after spawn. we'll fix this later. * io.c (pipe_open): ditto. * test/ruby/test_process.rb (test_execopts_env): upcase environment variable name for case insensitive platforms. * win32/win32.c (init_env): set USER environment variable only when USERNAME is available. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 20 +++++++ include/ruby/intern.h | 1 + io.c | 15 ++++++ process.c | 130 +++++++++++++++++++++++++++++++++++++++------- test/ruby/test_process.rb | 4 +- win32/win32.c | 5 +- 6 files changed, 152 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7401c22101..51fb2f7d59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +Mon May 12 23:05:24 2008 NAKAMURA Usaku + + * process.c, include/ruby/intern.h (rb_run_exec_options): externed. + + * process.c (save_redirect_fd, save_env_i, save_env, run_exec_dup2, + run_exec_open, run_exec_pgroup, run_exec_rlimit, rb_run_exec_options): + save parent's process environments. + !!!remark!!! these are not thread-safe. + + * process.c (rb_spawn_internal): remove calling run_exec_options() + because cannot restore after spawn. we'll fix this later. + + * io.c (pipe_open): ditto. + + * test/ruby/test_process.rb (test_execopts_env): upcase environment + variable name for case insensitive platforms. + + * win32/win32.c (init_env): set USER environment variable only when + USERNAME is available. + Mon May 12 22:23:01 2008 Tanaka Akira * lib/date.rb (once): use Object#object_id instead of Symbol#to_i. diff --git a/include/ruby/intern.h b/include/ruby/intern.h index 8b31576c5e..b95f2d02d3 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -457,6 +457,7 @@ int rb_proc_exec(const char*); VALUE rb_exec_arg_init(int argc, VALUE *argv, int accept_shell, struct rb_exec_arg *e); int rb_exec_arg_addopt(struct rb_exec_arg *e, VALUE key, VALUE val); void rb_exec_arg_fixup(struct rb_exec_arg *e); +int rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s); int rb_exec(const struct rb_exec_arg*); rb_pid_t rb_fork(int*, int (*)(void*), void*, VALUE); VALUE rb_f_exec(int,VALUE*); diff --git a/io.c b/io.c index 6bd0037d22..b5df75bc6d 100644 --- a/io.c +++ b/io.c @@ -3692,6 +3692,7 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *mode) int openmode = rb_io_mode_modenum(mode); const char *exename = NULL; volatile VALUE cmdbuf; + struct rb_exec_arg sarg; #endif FILE *fp = 0; int fd = -1; @@ -3822,6 +3823,10 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *mode) cmd = rb_w32_join_argv(RSTRING_PTR(cmdbuf), args); rb_str_resize(argbuf, 0); } + if (eargp) { + rb_exec_arg_fixup(eargp); + rb_run_exec_options(eargp, &sarg); + } while ((pid = rb_w32_pipe_exec(cmd, exename, openmode, &fd, &write_fd)) == -1) { /* exec failed */ switch (errno) { @@ -3832,16 +3837,26 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *mode) rb_thread_sleep(1); break; default: + if (eargp) + rb_run_exec_options(&sarg, NULL); rb_sys_fail(cmd); break; } } + if (eargp) + rb_run_exec_options(&sarg, NULL); #else if (argc) { prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" ")); cmd = StringValueCStr(prog); } + if (eargp) { + rb_exec_arg_fixup(eargp); + rb_run_exec_options(eargp, &sarg); + } fp = popen(cmd, mode); + if (eargp) + rb_run_exec_options(&sarg, NULL); if (!fp) rb_sys_fail(RSTRING_PTR(prog)); fd = fileno(fp); #endif diff --git a/process.c b/process.c index a82baa24e1..b5be40372d 100644 --- a/process.c +++ b/process.c @@ -1782,6 +1782,54 @@ redirect_open(const char *pathname, int flags, mode_t perm) #define redirect_open(pathname, flags, perm) open(pathname, flags, perm) #endif +static int +save_redirect_fd(int fd, VALUE save) +{ + if (!NIL_P(save)) { + VALUE newary; + int save_fd = redirect_dup(fd); + if (save_fd == -1) return -1; + newary = rb_ary_entry(save, EXEC_OPTION_DUP2); + if (NIL_P(newary)) { + newary = hide_obj(rb_ary_new()); + rb_ary_store(save, EXEC_OPTION_DUP2, newary); + } + rb_ary_push(newary, + hide_obj(rb_assoc_new(INT2FIX(fd), INT2FIX(save_fd)))); + + newary = rb_ary_entry(save, EXEC_OPTION_CLOSE); + if (NIL_P(newary)) { + newary = hide_obj(rb_ary_new()); + rb_ary_store(save, EXEC_OPTION_CLOSE, newary); + } + rb_ary_push(newary, hide_obj(rb_assoc_new(INT2FIX(save_fd), Qnil))); + } + + return 0; +} + +static VALUE +save_env_i(VALUE i, VALUE ary, int argc, VALUE *argv) +{ + rb_ary_push(ary, hide_obj(rb_ary_dup(argv[0]))); + return Qnil; +} + +static void +save_env(VALUE save) +{ + if (!NIL_P(save) && NIL_P(rb_ary_entry(save, EXEC_OPTION_ENV))) { + VALUE env = rb_const_get(rb_cObject, rb_intern("ENV")); + if (RTEST(env)) { + VALUE ary = hide_obj(rb_ary_new()); + rb_block_call(env, rb_intern("each"), 0, 0, save_env_i, + (VALUE)ary); + rb_ary_store(save, EXEC_OPTION_ENV, ary); + } + rb_ary_store(save, EXEC_OPTION_UNSETENV_OTHERS, Qtrue); + } +} + static int intcmp(const void *a, const void *b) { @@ -1789,7 +1837,7 @@ intcmp(const void *a, const void *b) } static int -run_exec_dup2(VALUE ary) +run_exec_dup2(VALUE ary, VALUE save) { int n, i; int ret; @@ -1837,6 +1885,8 @@ run_exec_dup2(VALUE ary) for (i = 0; i < n; i++) { int j = i; while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) { + if (save_redirect_fd(pairs[j].newfd, save) < 0) + return -1; ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd); if (ret == -1) goto fail; @@ -1919,7 +1969,7 @@ run_exec_close(VALUE ary) } static int -run_exec_open(VALUE ary) +run_exec_open(VALUE ary, VALUE save) { int i, ret; @@ -1940,6 +1990,8 @@ run_exec_open(VALUE ary) need_close = 0; } else { + if (save_redirect_fd(fd, save) < 0) + return -1; ret = redirect_dup2(fd2, fd); if (ret == -1) return -1; } @@ -1955,14 +2007,18 @@ run_exec_open(VALUE ary) #ifdef HAVE_SETPGID static int -run_exec_pgroup(VALUE obj) +run_exec_pgroup(VALUE obj, VALUE save) { /* * If FD_CLOEXEC is available, rb_fork waits the child's execve. * So setpgid is done in the child when rb_fork is returned in the parent. * No race condition, even without setpgid from the parent. * (Is there an environment which has setpgid but FD_CLOEXEC?) - */ + */ + if (!NIL_P(save)) { + /* maybe meaningless with no fork environment... */ + rb_ary_store(save, EXEC_OPTION_PGROUP, PIDT2NUM(getpgrp())); + } pid_t pgroup = NUM2PIDT(obj); if (pgroup == 0) { pgroup = getpid(); @@ -1973,13 +2029,26 @@ run_exec_pgroup(VALUE obj) #ifdef RLIM2NUM static int -run_exec_rlimit(VALUE ary) +run_exec_rlimit(VALUE ary, VALUE save) { int i; for (i = 0; i < RARRAY_LEN(ary); i++) { VALUE elt = RARRAY_PTR(ary)[i]; int rtype = NUM2INT(RARRAY_PTR(elt)[0]); struct rlimit rlim; + if (!NIL_P(save)) { + if (getrlimit(rtype, &rlim) == -1) + return -1; + VALUE tmp = hide_obj(rb_ary_new3(3, RARRAY_PTR(elt)[0], + RLIM2NUM(rlim.rlim_cur), + RLIM2NUM(rlim.rlim_max))); + VALUE newary = rb_ary_entry(save, EXEC_OPTION_RLIMIT); + if (NIL_P(newary)) { + newary = hide_obj(rb_ary_new()); + rb_ary_store(save, EXEC_OPTION_RLIMIT, newary); + } + rb_ary_push(newary, tmp); + } rlim.rlim_cur = NUM2RLIM(RARRAY_PTR(elt)[1]); rlim.rlim_max = NUM2RLIM(RARRAY_PTR(elt)[2]); if (setrlimit(rtype, &rlim) == -1) @@ -1989,19 +2058,28 @@ run_exec_rlimit(VALUE ary) } #endif -static int -run_exec_options(const struct rb_exec_arg *e) +int +rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s) { VALUE options = e->options; + VALUE soptions = Qnil; VALUE obj; if (!RTEST(options)) return 0; + if (s) { + s->argc = 0; + s->argv = NULL; + s->prog = NULL; + s->options = soptions = hide_obj(rb_ary_new()); + s->redirect_fds = Qnil; + } + #ifdef HAVE_SETPGID obj = rb_ary_entry(options, EXEC_OPTION_PGROUP); if (RTEST(obj)) { - if (run_exec_pgroup(obj) == -1) + if (run_exec_pgroup(obj, soptions) == -1) return -1; } #endif @@ -2009,19 +2087,21 @@ run_exec_options(const struct rb_exec_arg *e) #ifdef RLIM2NUM obj = rb_ary_entry(options, EXEC_OPTION_RLIMIT); if (!NIL_P(obj)) { - if (run_exec_rlimit(obj) == -1) + if (run_exec_rlimit(obj, soptions) == -1) return -1; } #endif obj = rb_ary_entry(options, EXEC_OPTION_UNSETENV_OTHERS); if (RTEST(obj)) { + save_env(soptions); rb_env_clear(); } obj = rb_ary_entry(options, EXEC_OPTION_ENV); if (!NIL_P(obj)) { int i; + save_env(soptions); for (i = 0; i < RARRAY_LEN(obj); i++) { VALUE pair = RARRAY_PTR(obj)[i]; VALUE key = RARRAY_PTR(pair)[0]; @@ -2035,6 +2115,11 @@ run_exec_options(const struct rb_exec_arg *e) obj = rb_ary_entry(options, EXEC_OPTION_CHDIR); if (!NIL_P(obj)) { + if (!NIL_P(soptions)) { + char *cwd = my_getcwd(); + rb_ary_store(soptions, EXEC_OPTION_CHDIR, + hide_obj(rb_str_new2(cwd))); + } if (chdir(RSTRING_PTR(obj)) == -1) return -1; } @@ -2042,19 +2127,25 @@ run_exec_options(const struct rb_exec_arg *e) obj = rb_ary_entry(options, EXEC_OPTION_UMASK); if (!NIL_P(obj)) { mode_t mask = NUM2LONG(obj); - umask(mask); /* never fail */ + mode_t oldmask = umask(mask); /* never fail */ + if (!NIL_P(soptions)) + rb_ary_store(soptions, EXEC_OPTION_UMASK, LONG2NUM(oldmask)); } obj = rb_ary_entry(options, EXEC_OPTION_DUP2); if (!NIL_P(obj)) { - if (run_exec_dup2(obj) == -1) + if (run_exec_dup2(obj, soptions) == -1) return -1; } obj = rb_ary_entry(options, EXEC_OPTION_CLOSE); if (!NIL_P(obj)) { - if (run_exec_close(obj) == -1) - return -1; + if (!NIL_P(soptions)) + rb_warn("cannot close fd before spawn"); + else { + if (run_exec_close(obj) == -1) + return -1; + } } #ifdef HAVE_FORK @@ -2066,7 +2157,7 @@ run_exec_options(const struct rb_exec_arg *e) obj = rb_ary_entry(options, EXEC_OPTION_OPEN); if (!NIL_P(obj)) { - if (run_exec_open(obj) == -1) + if (run_exec_open(obj, soptions) == -1) return -1; } @@ -2080,7 +2171,7 @@ rb_exec(const struct rb_exec_arg *e) VALUE *argv = e->argv; const char *prog = e->prog; - if (run_exec_options(e) < 0) { + if (rb_run_exec_options(e, NULL) < 0) { return -1; } @@ -2554,6 +2645,9 @@ rb_spawn_internal(int argc, VALUE *argv, int default_close_others) rb_pid_t status; VALUE prog; struct rb_exec_arg earg; +#if !defined HAVE_FORK + struct rb_exec_arg sarg; +#endif prog = rb_exec_arg_init(argc, argv, Qtrue, &earg); if (NIL_P(rb_ary_entry(earg.options, EXEC_OPTION_CLOSE_OTHERS))) { @@ -2566,11 +2660,9 @@ rb_spawn_internal(int argc, VALUE *argv, int default_close_others) status = rb_fork(&status, rb_exec_atfork, &earg, earg.redirect_fds); if (prog && earg.argc) earg.argv[0] = prog; #else - /* XXXXX: need to call this func, but cannot restore after spawn... - if (run_exec_options(&earg) < 0) { + if (rb_run_exec_options(&earg, &sarg) < 0) { return -1; } - */ argc = earg.argc; argv = earg.argv; @@ -2591,6 +2683,8 @@ rb_spawn_internal(int argc, VALUE *argv, int default_close_others) rb_last_status_set((status & 0xff) << 8, 0); # endif # endif + + rb_run_exec_options(&sarg, NULL); #endif return status; } diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb index 183bf10b83..d90fa06fb3 100644 --- a/test/ruby/test_process.rb +++ b/test/ruby/test_process.rb @@ -195,8 +195,8 @@ class TestProcess < Test::Unit::TestCase } h = {} - ENV.each {|k,v| h[k] = nil unless k == "PATH" } - IO.popen([h, RUBY, '-e', 'puts ENV.keys']) {|io| + ENV.each {|k,v| h[k] = nil unless k.upcase == "PATH" } + IO.popen([h, RUBY, '-e', 'puts ENV.keys.map{|e|e.upcase}']) {|io| assert_equal("PATH\n", io.read) } diff --git a/win32/win32.c b/win32/win32.c index 48be4df66e..abc62d9987 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -376,11 +376,10 @@ init_env(void) } if (!GetEnvironmentVariable("USER", env, sizeof env)) { - if (GetEnvironmentVariable("USERNAME", env, sizeof env) || - GetUserName(env, (len = sizeof env, &len))) { + if (GetEnvironmentVariable("USERNAME", env, sizeof env)) { SetEnvironmentVariable("USER", env); } - else { + else if (!GetUserName(env, (len = sizeof env, &len))) { NTLoginName = ""; return; } -- cgit v1.2.3