[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]