mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* 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(). git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35882 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
694035eb35
commit
f4f28bf75f
4 changed files with 117 additions and 51 deletions
20
ChangeLog
20
ChangeLog
|
@ -1,3 +1,23 @@
|
||||||
|
Sun Jun 3 17:23:52 2012 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
|
* 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@ruby-lang.org>
|
Sun Jun 3 16:33:58 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* marshal.c: revert r35879 "now marshal_{load|dump} are external."
|
* marshal.c: revert r35879 "now marshal_{load|dump} are external."
|
||||||
|
|
|
@ -592,6 +592,8 @@ struct rb_exec_arg {
|
||||||
VALUE options;
|
VALUE options;
|
||||||
VALUE redirect_fds;
|
VALUE redirect_fds;
|
||||||
VALUE progname;
|
VALUE progname;
|
||||||
|
VALUE envp_str;
|
||||||
|
VALUE envp_buf;
|
||||||
};
|
};
|
||||||
int rb_proc_exec_n(int, VALUE*, const char*);
|
int rb_proc_exec_n(int, VALUE*, const char*);
|
||||||
int rb_proc_exec(const char*);
|
int rb_proc_exec(const char*);
|
||||||
|
|
138
process.c
138
process.c
|
@ -1068,13 +1068,13 @@ exec_with_sh(const char *prog, char **argv)
|
||||||
|
|
||||||
#ifdef __native_client__
|
#ifdef __native_client__
|
||||||
static int
|
static int
|
||||||
proc_exec_v(char **argv, const char *prog)
|
proc_exec_v(char **argv, const char *prog, VALUE envp_str)
|
||||||
{
|
{
|
||||||
rb_notimplement();
|
rb_notimplement();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static int
|
static int
|
||||||
proc_exec_v(char **argv, const char *prog)
|
proc_exec_v(char **argv, const char *prog, VALUE envp_str)
|
||||||
{
|
{
|
||||||
char fbuf[MAXPATHLEN];
|
char fbuf[MAXPATHLEN];
|
||||||
# if defined(__EMX__) || defined(OS2)
|
# if defined(__EMX__) || defined(OS2)
|
||||||
|
@ -1118,6 +1118,9 @@ proc_exec_v(char **argv, const char *prog)
|
||||||
}
|
}
|
||||||
# endif /* __EMX__ */
|
# endif /* __EMX__ */
|
||||||
before_exec();
|
before_exec();
|
||||||
|
if (envp_str)
|
||||||
|
execve(prog, argv, (char **)RSTRING_PTR(envp_str));
|
||||||
|
else
|
||||||
execv(prog, argv);
|
execv(prog, argv);
|
||||||
preserving_errno(try_with_sh(prog, argv); after_exec());
|
preserving_errno(try_with_sh(prog, argv); after_exec());
|
||||||
# if defined(__EMX__) || defined(OS2)
|
# if defined(__EMX__) || defined(OS2)
|
||||||
|
@ -1130,8 +1133,8 @@ proc_exec_v(char **argv, const char *prog)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int
|
static int
|
||||||
rb_proc_exec_n(int argc, VALUE *argv, const char *prog)
|
rb_proc_exec_ne(int argc, VALUE *argv, const char *prog, VALUE envp_str)
|
||||||
{
|
{
|
||||||
char **args;
|
char **args;
|
||||||
int i;
|
int i;
|
||||||
|
@ -1144,12 +1147,18 @@ rb_proc_exec_n(int argc, VALUE *argv, const char *prog)
|
||||||
}
|
}
|
||||||
args[i] = 0;
|
args[i] = 0;
|
||||||
if (args[0]) {
|
if (args[0]) {
|
||||||
ret = proc_exec_v(args, prog);
|
ret = proc_exec_v(args, prog, envp_str);
|
||||||
}
|
}
|
||||||
ALLOCV_END(v);
|
ALLOCV_END(v);
|
||||||
return ret;
|
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__
|
#ifdef __native_client__
|
||||||
int
|
int
|
||||||
rb_proc_exec(const char *str)
|
rb_proc_exec(const char *str)
|
||||||
|
@ -1217,7 +1226,7 @@ rb_proc_exec(const char *str)
|
||||||
*a = NULL;
|
*a = NULL;
|
||||||
}
|
}
|
||||||
if (argv[0]) {
|
if (argv[0]) {
|
||||||
ret = proc_exec_v(argv, 0);
|
ret = proc_exec_v(argv, NULL, Qfalse);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
|
@ -1855,10 +1864,81 @@ rb_exec_arg_init(int argc, VALUE *argv, int accept_shell, struct rb_exec_arg *e)
|
||||||
return prog;
|
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
|
void
|
||||||
rb_exec_arg_fixup(struct rb_exec_arg *e)
|
rb_exec_arg_fixup(struct rb_exec_arg *e)
|
||||||
{
|
{
|
||||||
|
VALUE unsetenv_others, envopts;
|
||||||
|
|
||||||
e->redirect_fds = check_exec_fds(e->options);
|
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 @@ save_redirect_fd(int fd, VALUE save, char *errmsg, size_t errmsg_buflen)
|
||||||
return 0;
|
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
|
static int
|
||||||
intcmp(const void *a, const void *b)
|
intcmp(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
|
@ -2372,6 +2430,7 @@ rb_run_exec_options_err(const struct rb_exec_arg *e, struct rb_exec_arg *s, char
|
||||||
s->options = soptions = hide_obj(rb_ary_new());
|
s->options = soptions = hide_obj(rb_ary_new());
|
||||||
s->redirect_fds = Qnil;
|
s->redirect_fds = Qnil;
|
||||||
s->progname = Qnil;
|
s->progname = Qnil;
|
||||||
|
s->envp_str = s->envp_buf = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SETPGID
|
#ifdef HAVE_SETPGID
|
||||||
|
@ -2390,27 +2449,6 @@ rb_run_exec_options_err(const struct rb_exec_arg *e, struct rb_exec_arg *s, char
|
||||||
}
|
}
|
||||||
#endif
|
#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);
|
obj = rb_ary_entry(options, EXEC_OPTION_UMASK);
|
||||||
if (!NIL_P(obj)) {
|
if (!NIL_P(obj)) {
|
||||||
mode_t mask = NUM2MODET(obj);
|
mode_t mask = NUM2MODET(obj);
|
||||||
|
@ -2492,7 +2530,7 @@ rb_exec_err(const struct rb_exec_arg *e, char *errmsg, size_t errmsg_buflen)
|
||||||
rb_proc_exec(prog);
|
rb_proc_exec(prog);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rb_proc_exec_n(argc, argv, prog);
|
rb_proc_exec_ne(argc, argv, prog, e->envp_str);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -303,6 +303,12 @@ class TestProcess < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
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
|
def test_execopts_unsetenv_others
|
||||||
h = {}
|
h = {}
|
||||||
MANDATORY_ENVS.each {|k| e = ENV[k] and h[k] = e}
|
MANDATORY_ENVS.each {|k| e = ENV[k] and h[k] = e}
|
||||||
|
|
Loading…
Reference in a new issue