[pypy-svn] r49252 - in pypy/dist/pypy: module/posix module/posix/test rpython/module rpython/module/test

exarkun at codespeak.net exarkun at codespeak.net
Sat Dec 1 18:05:47 CET 2007


Author: exarkun
Date: Sat Dec  1 18:05:46 2007
New Revision: 49252

Added:
   pypy/dist/pypy/rpython/module/test/execve_tests.py
Modified:
   pypy/dist/pypy/module/posix/__init__.py
   pypy/dist/pypy/module/posix/test/test_posix2.py
   pypy/dist/pypy/rpython/module/ll_os.py
   pypy/dist/pypy/rpython/module/test/test_ll_os.py
Log:
llimpl for os.execve

Modified: pypy/dist/pypy/module/posix/__init__.py
==============================================================================
--- pypy/dist/pypy/module/posix/__init__.py	(original)
+++ pypy/dist/pypy/module/posix/__init__.py	Sat Dec  1 18:05:46 2007
@@ -75,7 +75,7 @@
         interpleveldefs['waitpid'] = 'interp_posix.waitpid'
     if hasattr(os, 'execv'):
         interpleveldefs['execv'] = 'interp_posix.execv'
-    if hasattr(os, 'execve')   and 0:     # XXX XXX in-progress
+    if hasattr(os, 'execve'):
         interpleveldefs['execve'] = 'interp_posix.execve'
     if False and hasattr(os, 'uname'):
         interpleveldefs['uname'] = 'interp_posix.uname'

Modified: pypy/dist/pypy/module/posix/test/test_posix2.py
==============================================================================
--- pypy/dist/pypy/module/posix/test/test_posix2.py	(original)
+++ pypy/dist/pypy/module/posix/test/test_posix2.py	Sat Dec  1 18:05:46 2007
@@ -206,8 +206,9 @@
             t([3, "a"])
 
         def test_execve(self):
-            skip("Not implemented")
             os = self.posix
+            if not hasattr(os, "fork"):
+                skip("Need fork() to test execve()")
             pid = os.fork()
             if pid == 0:
                 os.execve("/usr/bin/env", ["env", "python", "-c", "import os; open('onefile', 'w').write(os.environ['ddd'])"], {'ddd':'xxx'})

Modified: pypy/dist/pypy/rpython/module/ll_os.py
==============================================================================
--- pypy/dist/pypy/rpython/module/ll_os.py	(original)
+++ pypy/dist/pypy/rpython/module/ll_os.py	Sat Dec  1 18:05:46 2007
@@ -137,6 +137,36 @@
         return extdef([str, [str]], s_ImpossibleValue, llimpl=execv_llimpl,
                       export_name="ll_os.ll_os_execv")
 
+
+    @registering_if(os, 'execve')
+    def register_os_execve(self):
+        os_execve = self.llexternal(
+            'execve', [rffi.CCHARP, rffi.CCHARPP, rffi.CCHARPP], rffi.INT)
+
+        def execve_llimpl(path, args, env):
+            # XXX Check path, args, env for \0 and raise TypeErrors as
+            # appropriate
+            envstrs = []
+            for item in env.iteritems():
+                envstrs.append("%s=%s" % item)
+
+            l_args = rffi.liststr2charpp(args)
+            l_env = rffi.liststr2charpp(envstrs)
+            os_execve(path, l_args, l_env)
+
+            # XXX untested
+            rffi.free_charpp(l_env)
+            rffi.free_charpp(l_args)
+
+            raise OSError(rposix.get_errno(), "execve failed")
+
+        return extdef(
+            [str, [str], {str: str}],
+            s_ImpossibleValue,
+            llimpl=execve_llimpl,
+            export_name="ll_os.ll_os_execve")
+
+
     @registering_if(posix, 'spawnv')
     def register_os_spawnv(self):
         os_spawnv = self.llexternal('spawnv',

Added: pypy/dist/pypy/rpython/module/test/execve_tests.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/module/test/execve_tests.py	Sat Dec  1 18:05:46 2007
@@ -0,0 +1,25 @@
+
+"""
+Functions which call the llimpl execve function with various arguments.  Since
+execve replaces the process with a new one in the successful case, these are
+here to be run as a child process of the test process.
+"""
+
+import os, sys
+
+from pypy.rpython.module.test.test_ll_os import EXECVE_ENV, getllimpl
+
+execve = getllimpl(os.execve)
+
+
+def execve_true():
+    execve("/bin/true", ["/bin/true"], {})
+
+def execve_false():
+    execve("/bin/false", ["/bin/false"], {})
+
+def execve_env():
+    execve("/usr/bin/env", ["/usr/bin/env"], EXECVE_ENV)
+
+if __name__ == '__main__':
+    globals()[sys.argv[1]]()

Modified: pypy/dist/pypy/rpython/module/test/test_ll_os.py
==============================================================================
--- pypy/dist/pypy/rpython/module/test/test_ll_os.py	(original)
+++ pypy/dist/pypy/rpython/module/test/test_ll_os.py	Sat Dec  1 18:05:46 2007
@@ -1,8 +1,11 @@
 import os
+from py.path import local
+
 from pypy.tool.udir import udir
 from pypy.translator.c.test.test_genc import compile
 
 from pypy.rpython import extregistry
+import errno
 import sys
 import py
 
@@ -58,6 +61,43 @@
     assert file(filename).read().strip() == '2'
     os.unlink(filename)
 
+
+EXECVE_ENV = {"foo": "bar", "baz": "quux"}
+execve_tests = str(local(__file__).dirpath().join('execve_tests.py'))
+
+def test_execve():
+    if os.name != 'posix':
+        py.test.skip('posix specific function')
+    base = sys.executable + " " + execve_tests + " "
+
+    # Test exit status and code
+    result = os.system(base + "execve_true")
+    assert os.WIFEXITED(result)
+    assert os.WEXITSTATUS(result) == 0
+    result = os.system(base + "execve_false")
+    assert os.WIFEXITED(result)
+    assert os.WEXITSTATUS(result) == 1
+
+    # Test environment
+    result = os.popen(base + "execve_env").read()
+    assert dict([line.split('=') for line in result.splitlines()]) == EXECVE_ENV
+
+    # These won't actually execute anything, so they don't need a child process
+    # helper.
+    execve = getllimpl(os.execve)
+
+    # If the target does not exist, an OSError should result
+    info = py.test.raises(
+        OSError, execve, execve_tests + "-non-existent", [], {})
+    assert info.value.errno == errno.ENOENT
+
+    # If the target is not executable, an OSError should result
+    info = py.test.raises(
+        OSError, execve, execve_tests, [], {})
+    assert info.value.errno == errno.EACCES
+
+
+
 class ExpectTestOs:
     def setup_class(cls):
         if not hasattr(os, 'ttyname'):



More information about the Pypy-commit mailing list