ruby-changes:4902
From: ko1@a...
Date: Mon, 12 May 2008 23:15:59 +0900 (JST)
Subject: [ruby-changes:4902] usa - Ruby:r16395 (trunk): * process.c, include/ruby/intern.h (rb_run_exec_options): externed.
usa 2008-05-12 23:15:32 +0900 (Mon, 12 May 2008) New Revision: 16395 Modified files: trunk/ChangeLog trunk/include/ruby/intern.h trunk/io.c trunk/process.c trunk/test/ruby/test_process.rb trunk/win32/win32.c Log: * 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. http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/win32/win32.c?r1=16395&r2=16394&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/ruby/test_process.rb?r1=16395&r2=16394&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=16395&r2=16394&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/io.c?r1=16395&r2=16394&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/process.c?r1=16395&r2=16394&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/include/ruby/intern.h?r1=16395&r2=16394&diff_format=u Index: include/ruby/intern.h =================================================================== --- include/ruby/intern.h (revision 16394) +++ include/ruby/intern.h (revision 16395) @@ -457,6 +457,7 @@ 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*); Index: ChangeLog =================================================================== --- ChangeLog (revision 16394) +++ ChangeLog (revision 16395) @@ -1,3 +1,23 @@ +Mon May 12 23:05:24 2008 NAKAMURA Usaku <usa@r...> + + * 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 <akr@f...> * lib/date.rb (once): use Object#object_id instead of Symbol#to_i. Index: io.c =================================================================== --- io.c (revision 16394) +++ io.c (revision 16395) @@ -3692,6 +3692,7 @@ 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 @@ 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 @@ 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 Index: win32/win32.c =================================================================== --- win32/win32.c (revision 16394) +++ win32/win32.c (revision 16395) @@ -376,11 +376,10 @@ } 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 = "<Unknown>"; return; } Index: process.c =================================================================== --- process.c (revision 16394) +++ process.c (revision 16395) @@ -1783,13 +1783,61 @@ #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) { return *(int*)a - *(int*)b; } static int -run_exec_dup2(VALUE ary) +run_exec_dup2(VALUE ary, VALUE save) { int n, i; int ret; @@ -1837,6 +1885,8 @@ 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 @@ } static int -run_exec_open(VALUE ary) +run_exec_open(VALUE ary, VALUE save) { int i, ret; @@ -1940,6 +1990,8 @@ 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 @@ #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 @@ #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 @@ } #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 @@ #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 @@ 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 @@ 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 @@ 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 @@ 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_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 @@ 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_last_status_set((status & 0xff) << 8, 0); # endif # endif + + rb_run_exec_options(&sarg, NULL); #endif return status; } Index: test/ruby/test_process.rb =================================================================== --- test/ruby/test_process.rb (revision 16394) +++ test/ruby/test_process.rb (revision 16395) @@ -195,8 +195,8 @@ } 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) } -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/