ruby-changes:23831
From: akr <ko1@a...>
Date: Sun, 3 Jun 2012 17:30:00 +0900 (JST)
Subject: [ruby-changes:23831] akr:r35882 (trunk): * use execve() to preserve environment variables when exec method is
akr 2012-06-03 17:29:48 +0900 (Sun, 03 Jun 2012) New Revision: 35882 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=35882 Log: * use execve() to preserve environment variables when exec method is failed. [ruby-core:44093] [ruby-trunk - Bug #6249] * include/ruby/intern.h (rb_exec_arg): add envp_str and envp_buf field to store envp of execve(). * process.c (proc_exec_v): takes envp_str as an argument and use it for execve(). (rb_proc_exec_ne): extended version of rb_proc_exec_n(). (rb_proc_exec_n): use rb_proc_exec_ne(). (rb_proc_exec): follow proc_exec_v() change. (fill_envp_buf_i): new function. (rb_exec_arg_fixup): set up envp_str and envp_buf. (save_env_i): removed. (save_env): removed. (rb_run_exec_options_err): don't modify environment variables. (rb_exec_err): use rb_proc_exec_ne(). Modified files: trunk/ChangeLog trunk/include/ruby/intern.h trunk/process.c trunk/test/ruby/test_process.rb Index: include/ruby/intern.h =================================================================== --- include/ruby/intern.h (revision 35881) +++ include/ruby/intern.h (revision 35882) @@ -592,6 +592,8 @@ VALUE options; VALUE redirect_fds; VALUE progname; + VALUE envp_str; + VALUE envp_buf; }; int rb_proc_exec_n(int, VALUE*, const char*); int rb_proc_exec(const char*); Index: ChangeLog =================================================================== --- ChangeLog (revision 35881) +++ ChangeLog (revision 35882) @@ -1,3 +1,23 @@ +Sun Jun 3 17:23:52 2012 Tanaka Akira <akr@f...> + + * use execve() to preserve environment variables when exec method is + failed. [ruby-core:44093] [ruby-trunk - Bug #6249] + + * include/ruby/intern.h (rb_exec_arg): add envp_str and envp_buf field + to store envp of execve(). + + * process.c (proc_exec_v): takes envp_str as an argument and use it + for execve(). + (rb_proc_exec_ne): extended version of rb_proc_exec_n(). + (rb_proc_exec_n): use rb_proc_exec_ne(). + (rb_proc_exec): follow proc_exec_v() change. + (fill_envp_buf_i): new function. + (rb_exec_arg_fixup): set up envp_str and envp_buf. + (save_env_i): removed. + (save_env): removed. + (rb_run_exec_options_err): don't modify environment variables. + (rb_exec_err): use rb_proc_exec_ne(). + Sun Jun 3 16:33:58 2012 Nobuyoshi Nakada <nobu@r...> * marshal.c: revert r35879 "now marshal_{load|dump} are external." Index: process.c =================================================================== --- process.c (revision 35881) +++ process.c (revision 35882) @@ -1068,13 +1068,13 @@ #ifdef __native_client__ static int -proc_exec_v(char **argv, const char *prog) +proc_exec_v(char **argv, const char *prog, VALUE envp_str) { rb_notimplement(); } #else static int -proc_exec_v(char **argv, const char *prog) +proc_exec_v(char **argv, const char *prog, VALUE envp_str) { char fbuf[MAXPATHLEN]; # if defined(__EMX__) || defined(OS2) @@ -1118,7 +1118,10 @@ } # endif /* __EMX__ */ before_exec(); - execv(prog, argv); + if (envp_str) + execve(prog, argv, (char **)RSTRING_PTR(envp_str)); + else + execv(prog, argv); preserving_errno(try_with_sh(prog, argv); after_exec()); # if defined(__EMX__) || defined(OS2) if (new_argv) { @@ -1130,8 +1133,8 @@ } #endif -int -rb_proc_exec_n(int argc, VALUE *argv, const char *prog) +static int +rb_proc_exec_ne(int argc, VALUE *argv, const char *prog, VALUE envp_str) { char **args; int i; @@ -1144,12 +1147,18 @@ } args[i] = 0; if (args[0]) { - ret = proc_exec_v(args, prog); + ret = proc_exec_v(args, prog, envp_str); } ALLOCV_END(v); return ret; } +int +rb_proc_exec_n(int argc, VALUE *argv, const char *prog) +{ + return rb_proc_exec_ne(argc, argv, prog, Qfalse); +} + #ifdef __native_client__ int rb_proc_exec(const char *str) @@ -1217,7 +1226,7 @@ *a = NULL; } if (argv[0]) { - ret = proc_exec_v(argv, 0); + ret = proc_exec_v(argv, NULL, Qfalse); } else { errno = ENOENT; @@ -1855,10 +1864,81 @@ return prog; } +static int +fill_envp_buf_i(st_data_t st_key, st_data_t st_val, st_data_t arg) +{ + VALUE key = (VALUE)st_key; + VALUE val = (VALUE)st_val; + VALUE envp_buf = (VALUE)arg; + + rb_str_buf_cat2(envp_buf, StringValueCStr(key)); + rb_str_buf_cat2(envp_buf, "="); + rb_str_buf_cat2(envp_buf, StringValueCStr(val)); + rb_str_buf_cat(envp_buf, "", 1); /* append '\0' */ + + return ST_CONTINUE; +} + void rb_exec_arg_fixup(struct rb_exec_arg *e) { + VALUE unsetenv_others, envopts; + e->redirect_fds = check_exec_fds(e->options); + + unsetenv_others = rb_ary_entry(e->options, EXEC_OPTION_UNSETENV_OTHERS); + envopts = rb_ary_entry(e->options, EXEC_OPTION_ENV); + if (RTEST(unsetenv_others) || !NIL_P(envopts)) { + VALUE envtbl, envp_str, envp_buf; + char *p, *ep; + if (RTEST(unsetenv_others)) { + envtbl = rb_hash_new(); + } + else { + envtbl = rb_const_get(rb_cObject, rb_intern("ENV")); + envtbl = rb_convert_type(envtbl, T_HASH, "Hash", "to_hash"); + } + hide_obj(envtbl); + if (!NIL_P(envopts)) { + st_table *stenv = RHASH_TBL(envtbl); + long i; + for (i = 0; i < RARRAY_LEN(envopts); i++) { + VALUE pair = RARRAY_PTR(envopts)[i]; + VALUE key = RARRAY_PTR(pair)[0]; + VALUE val = RARRAY_PTR(pair)[1]; + if (NIL_P(val)) { + st_data_t stkey = (st_data_t)key; + st_delete(stenv, &stkey, NULL); + } + else { + st_insert(stenv, (st_data_t)key, (st_data_t)val); + } + } + } + envp_buf = rb_str_buf_new(0); + hide_obj(envp_buf); + st_foreach(RHASH_TBL(envtbl), fill_envp_buf_i, (st_data_t)envp_buf); + envp_str = rb_str_buf_new(sizeof(char*) * (RHASH_SIZE(envtbl) + 1)); + hide_obj(envp_str); + p = RSTRING_PTR(envp_buf); + ep = p + RSTRING_LEN(envp_buf); + while (p < ep) { + rb_str_buf_cat(envp_str, (char *)&p, sizeof(p)); + p += strlen(p) + 1; + } + p = NULL; + rb_str_buf_cat(envp_str, (char *)&p, sizeof(p)); + e->envp_str = envp_str; + e->envp_buf = envp_buf; + + /* + char **tmp_envp = (char **)RSTRING_PTR(envp_str); + while (*tmp_envp) { + printf("%s\n", *tmp_envp); + tmp_envp++; + } + */ + } } /* @@ -2027,28 +2107,6 @@ 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) { @@ -2372,6 +2430,7 @@ s->options = soptions = hide_obj(rb_ary_new()); s->redirect_fds = Qnil; s->progname = Qnil; + s->envp_str = s->envp_buf = 0; } #ifdef HAVE_SETPGID @@ -2390,27 +2449,6 @@ } #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)) { - long i; - save_env(soptions); - for (i = 0; i < RARRAY_LEN(obj); i++) { - VALUE pair = RARRAY_PTR(obj)[i]; - VALUE key = RARRAY_PTR(pair)[0]; - VALUE val = RARRAY_PTR(pair)[1]; - if (NIL_P(val)) - ruby_setenv(StringValueCStr(key), 0); - else - ruby_setenv(StringValueCStr(key), StringValueCStr(val)); - } - } - obj = rb_ary_entry(options, EXEC_OPTION_UMASK); if (!NIL_P(obj)) { mode_t mask = NUM2MODET(obj); @@ -2492,7 +2530,7 @@ rb_proc_exec(prog); } else { - rb_proc_exec_n(argc, argv, prog); + rb_proc_exec_ne(argc, argv, prog, e->envp_str); } return -1; } Index: test/ruby/test_process.rb =================================================================== --- test/ruby/test_process.rb (revision 35881) +++ test/ruby/test_process.rb (revision 35882) @@ -303,6 +303,12 @@ end end + def test_execopts_preserve_env_on_exec_failure + ENV["mgg"] = nil + assert_raise(Errno::ENOENT) { Process.exec({"mgg" => "mggoo"}, "/nonexistent") } + assert_equal(nil, ENV["mgg"], "[ruby-core:44093] [ruby-trunk - Bug #6249]") + end + def test_execopts_unsetenv_others h = {} MANDATORY_ENVS.each {|k| e = ENV[k] and h[k] = e} -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/