From 92b8322e7ea04b239cb1cb87b78d952f13ddfebb Mon Sep 17 00:00:00 2001 From: Joannah Nanjekye <33177550+nanjekyejoannah@users.noreply.github.com> Date: Wed, 16 Jan 2019 16:29:26 +0300 Subject: bpo-35674: Add os.posix_spawnp() (GH-11554) Add a new os.posix_spawnp() function. --- Doc/library/os.rst | 17 ++ Lib/test/test_posix.py | 190 +++++++++++++-------- .../2019-01-14-14-13-08.bpo-35674.kamWqz.rst | 2 + Modules/clinic/posixmodule.c.h | 75 +++++++- Modules/posixmodule.c | 135 +++++++++++---- aclocal.m4 | 8 +- configure | 2 +- configure.ac | 2 +- pyconfig.h.in | 3 + 9 files changed, 322 insertions(+), 112 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2019-01-14-14-13-08.bpo-35674.kamWqz.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 16250e2..2aa51f8 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3396,6 +3396,10 @@ written in Python, such as a mail server's external command delivery program. The positional-only arguments *path*, *args*, and *env* are similar to :func:`execve`. + The *path* parameter is the path to the executable file.The *path* should + contain a directory.Use :func:`posix_spawnp` to pass an executable file + without directory. + The *file_actions* argument may be a sequence of tuples describing actions to take on specific file descriptors in the child process between the C library implementation's :c:func:`fork` and :c:func:`exec` steps. @@ -3459,6 +3463,19 @@ written in Python, such as a mail server's external command delivery program. .. versionadded:: 3.7 +.. function:: posix_spawnp(path, argv, env, *, file_actions=None, \ + setpgroup=None, resetids=False, setsigmask=(), \ + setsigdef=(), scheduler=None) + + Wraps the :c:func:`posix_spawnp` C library API for use from Python. + + Similar to :func:`posix_spawn` except that the system searches + for the *executable* file in the list of directories specified by the + :envvar:`PATH` environment variable (in the same way as for ``execvp(3)``). + + .. versionadded:: 3.8 + + .. function:: register_at_fork(*, before=None, after_in_parent=None, \ after_in_child=None) diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index d7e512c..79fc3c2 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -1489,10 +1489,10 @@ class PosixGroupsTester(unittest.TestCase): self.assertListEqual(groups, posix.getgroups()) -@unittest.skipUnless(hasattr(os, 'posix_spawn'), "test needs os.posix_spawn") -class TestPosixSpawn(unittest.TestCase): - # Program which does nothing and exit with status 0 (success) +class _PosixSpawnMixin: + # Program which does nothing and exits with status 0 (success) NOOP_PROGRAM = (sys.executable, '-I', '-S', '-c', 'pass') + spawn_func = None def python_args(self, *args): # Disable site module to avoid side effects. For example, @@ -1511,7 +1511,7 @@ class TestPosixSpawn(unittest.TestCase): pidfile.write(str(os.getpid())) """ args = self.python_args('-c', script) - pid = posix.posix_spawn(args[0], args, os.environ) + pid = self.spawn_func(args[0], args, os.environ) self.assertEqual(os.waitpid(pid, 0), (pid, 0)) with open(pidfile) as f: self.assertEqual(f.read(), str(pid)) @@ -1519,9 +1519,9 @@ class TestPosixSpawn(unittest.TestCase): def test_no_such_executable(self): no_such_executable = 'no_such_executable' try: - pid = posix.posix_spawn(no_such_executable, - [no_such_executable], - os.environ) + pid = self.spawn_func(no_such_executable, + [no_such_executable], + os.environ) except FileNotFoundError as exc: self.assertEqual(exc.filename, no_such_executable) else: @@ -1538,14 +1538,14 @@ class TestPosixSpawn(unittest.TestCase): envfile.write(os.environ['foo']) """ args = self.python_args('-c', script) - pid = posix.posix_spawn(args[0], args, - {**os.environ, 'foo': 'bar'}) + pid = self.spawn_func(args[0], args, + {**os.environ, 'foo': 'bar'}) self.assertEqual(os.waitpid(pid, 0), (pid, 0)) with open(envfile) as f: self.assertEqual(f.read(), 'bar') def test_empty_file_actions(self): - pid = posix.posix_spawn( + pid = self.spawn_func( self.NOOP_PROGRAM[0], self.NOOP_PROGRAM, os.environ, @@ -1554,7 +1554,7 @@ class TestPosixSpawn(unittest.TestCase): self.assertEqual(os.waitpid(pid, 0), (pid, 0)) def test_resetids_explicit_default(self): - pid = posix.posix_spawn( + pid = self.spawn_func( sys.executable, [sys.executable, '-c', 'pass'], os.environ, @@ -1563,7 +1563,7 @@ class TestPosixSpawn(unittest.TestCase): self.assertEqual(os.waitpid(pid, 0), (pid, 0)) def test_resetids(self): - pid = posix.posix_spawn( + pid = self.spawn_func( sys.executable, [sys.executable, '-c', 'pass'], os.environ, @@ -1573,12 +1573,12 @@ class TestPosixSpawn(unittest.TestCase): def test_resetids_wrong_type(self): with self.assertRaises(TypeError): - posix.posix_spawn(sys.executable, - [sys.executable, "-c", "pass"], - os.environ, resetids=None) + self.spawn_func(sys.executable, + [sys.executable, "-c", "pass"], + os.environ, resetids=None) def test_setpgroup(self): - pid = posix.posix_spawn( + pid = self.spawn_func( sys.executable, [sys.executable, '-c', 'pass'], os.environ, @@ -1588,9 +1588,9 @@ class TestPosixSpawn(unittest.TestCase): def test_setpgroup_wrong_type(self): with self.assertRaises(TypeError): - posix.posix_spawn(sys.executable, - [sys.executable, "-c", "pass"], - os.environ, setpgroup="023") + self.spawn_func(sys.executable, + [sys.executable, "-c", "pass"], + os.environ, setpgroup="023") @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), 'need signal.pthread_sigmask()') @@ -1599,7 +1599,7 @@ class TestPosixSpawn(unittest.TestCase): import signal signal.raise_signal(signal.SIGUSR1)""") - pid = posix.posix_spawn( + pid = self.spawn_func( sys.executable, [sys.executable, '-c', code], os.environ, @@ -1609,18 +1609,18 @@ class TestPosixSpawn(unittest.TestCase): def test_setsigmask_wrong_type(self): with self.assertRaises(TypeError): - posix.posix_spawn(sys.executable, - [sys.executable, "-c", "pass"], - os.environ, setsigmask=34) + self.spawn_func(sys.executable, + [sys.executable, "-c", "pass"], + os.environ, setsigmask=34) with self.assertRaises(TypeError): - posix.posix_spawn(sys.executable, - [sys.executable, "-c", "pass"], - os.environ, setsigmask=["j"]) + self.spawn_func(sys.executable, + [sys.executable, "-c", "pass"], + os.environ, setsigmask=["j"]) with self.assertRaises(ValueError): - posix.posix_spawn(sys.executable, - [sys.executable, "-c", "pass"], - os.environ, setsigmask=[signal.NSIG, - signal.NSIG+1]) + self.spawn_func(sys.executable, + [sys.executable, "-c", "pass"], + os.environ, setsigmask=[signal.NSIG, + signal.NSIG+1]) @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), 'need signal.pthread_sigmask()') @@ -1630,7 +1630,7 @@ class TestPosixSpawn(unittest.TestCase): import signal signal.raise_signal(signal.SIGUSR1)""") try: - pid = posix.posix_spawn( + pid = self.spawn_func( sys.executable, [sys.executable, '-c', code], os.environ, @@ -1646,17 +1646,17 @@ class TestPosixSpawn(unittest.TestCase): def test_setsigdef_wrong_type(self): with self.assertRaises(TypeError): - posix.posix_spawn(sys.executable, - [sys.executable, "-c", "pass"], - os.environ, setsigdef=34) + self.spawn_func(sys.executable, + [sys.executable, "-c", "pass"], + os.environ, setsigdef=34) with self.assertRaises(TypeError): - posix.posix_spawn(sys.executable, - [sys.executable, "-c", "pass"], - os.environ, setsigdef=["j"]) + self.spawn_func(sys.executable, + [sys.executable, "-c", "pass"], + os.environ, setsigdef=["j"]) with self.assertRaises(ValueError): - posix.posix_spawn(sys.executable, - [sys.executable, "-c", "pass"], - os.environ, setsigdef=[signal.NSIG, signal.NSIG+1]) + self.spawn_func(sys.executable, + [sys.executable, "-c", "pass"], + os.environ, setsigdef=[signal.NSIG, signal.NSIG+1]) @requires_sched @unittest.skipIf(sys.platform.startswith(('freebsd', 'netbsd')), @@ -1670,7 +1670,7 @@ class TestPosixSpawn(unittest.TestCase): sys.exit(101) if os.sched_getparam(0).sched_priority != {priority}: sys.exit(102)""") - pid = posix.posix_spawn( + pid = self.spawn_func( sys.executable, [sys.executable, '-c', code], os.environ, @@ -1690,7 +1690,7 @@ class TestPosixSpawn(unittest.TestCase): sys.exit(101) if os.sched_getparam(0).sched_priority != {priority}: sys.exit(102)""") - pid = posix.posix_spawn( + pid = self.spawn_func( sys.executable, [sys.executable, '-c', code], os.environ, @@ -1704,40 +1704,40 @@ class TestPosixSpawn(unittest.TestCase): (os.POSIX_SPAWN_CLOSE, 0), (os.POSIX_SPAWN_DUP2, 1, 4), ] - pid = posix.posix_spawn(self.NOOP_PROGRAM[0], - self.NOOP_PROGRAM, - os.environ, - file_actions=file_actions) + pid = self.spawn_func(self.NOOP_PROGRAM[0], + self.NOOP_PROGRAM, + os.environ, + file_actions=file_actions) self.assertEqual(os.waitpid(pid, 0), (pid, 0)) def test_bad_file_actions(self): args = self.NOOP_PROGRAM with self.assertRaises(TypeError): - posix.posix_spawn(args[0], args, os.environ, - file_actions=[None]) + self.spawn_func(args[0], args, os.environ, + file_actions=[None]) with self.assertRaises(TypeError): - posix.posix_spawn(args[0], args, os.environ, - file_actions=[()]) + self.spawn_func(args[0], args, os.environ, + file_actions=[()]) with self.assertRaises(TypeError): - posix.posix_spawn(args[0], args, os.environ, - file_actions=[(None,)]) + self.spawn_func(args[0], args, os.environ, + file_actions=[(None,)]) with self.assertRaises(TypeError): - posix.posix_spawn(args[0], args, os.environ, - file_actions=[(12345,)]) + self.spawn_func(args[0], args, os.environ, + file_actions=[(12345,)]) with self.assertRaises(TypeError): - posix.posix_spawn(args[0], args, os.environ, - file_actions=[(os.POSIX_SPAWN_CLOSE,)]) + self.spawn_func(args[0], args, os.environ, + file_actions=[(os.POSIX_SPAWN_CLOSE,)]) with self.assertRaises(TypeError): - posix.posix_spawn(args[0], args, os.environ, - file_actions=[(os.POSIX_SPAWN_CLOSE, 1, 2)]) + self.spawn_func(args[0], args, os.environ, + file_actions=[(os.POSIX_SPAWN_CLOSE, 1, 2)]) with self.assertRaises(TypeError): - posix.posix_spawn(args[0], args, os.environ, - file_actions=[(os.POSIX_SPAWN_CLOSE, None)]) + self.spawn_func(args[0], args, os.environ, + file_actions=[(os.POSIX_SPAWN_CLOSE, None)]) with self.assertRaises(ValueError): - posix.posix_spawn(args[0], args, os.environ, - file_actions=[(os.POSIX_SPAWN_OPEN, - 3, __file__ + '\0', - os.O_RDONLY, 0)]) + self.spawn_func(args[0], args, os.environ, + file_actions=[(os.POSIX_SPAWN_OPEN, + 3, __file__ + '\0', + os.O_RDONLY, 0)]) def test_open_file(self): outfile = support.TESTFN @@ -1752,8 +1752,8 @@ class TestPosixSpawn(unittest.TestCase): stat.S_IRUSR | stat.S_IWUSR), ] args = self.python_args('-c', script) - pid = posix.posix_spawn(args[0], args, os.environ, - file_actions=file_actions) + pid = self.spawn_func(args[0], args, os.environ, + file_actions=file_actions) self.assertEqual(os.waitpid(pid, 0), (pid, 0)) with open(outfile) as f: self.assertEqual(f.read(), 'hello') @@ -1770,8 +1770,8 @@ class TestPosixSpawn(unittest.TestCase): closefile.write('is closed %d' % e.errno) """ args = self.python_args('-c', script) - pid = posix.posix_spawn(args[0], args, os.environ, - file_actions=[(os.POSIX_SPAWN_CLOSE, 0),]) + pid = self.spawn_func(args[0], args, os.environ, + file_actions=[(os.POSIX_SPAWN_CLOSE, 0)]) self.assertEqual(os.waitpid(pid, 0), (pid, 0)) with open(closefile) as f: self.assertEqual(f.read(), 'is closed %d' % errno.EBADF) @@ -1788,16 +1788,64 @@ class TestPosixSpawn(unittest.TestCase): (os.POSIX_SPAWN_DUP2, childfile.fileno(), 1), ] args = self.python_args('-c', script) - pid = posix.posix_spawn(args[0], args, os.environ, - file_actions=file_actions) + pid = self.spawn_func(args[0], args, os.environ, + file_actions=file_actions) self.assertEqual(os.waitpid(pid, 0), (pid, 0)) with open(dupfile) as f: self.assertEqual(f.read(), 'hello') +@unittest.skipUnless(hasattr(os, 'posix_spawn'), "test needs os.posix_spawn") +class TestPosixSpawn(unittest.TestCase, _PosixSpawnMixin): + spawn_func = getattr(posix, 'posix_spawn', None) + + +@unittest.skipUnless(hasattr(os, 'posix_spawnp'), "test needs os.posix_spawnp") +class TestPosixSpawnP(unittest.TestCase, _PosixSpawnMixin): + spawn_func = getattr(posix, 'posix_spawnp', None) + + @support.skip_unless_symlink + def test_posix_spawnp(self): + # Use a symlink to create a program in its own temporary directory + temp_dir = tempfile.mkdtemp() + self.addCleanup(support.rmtree, temp_dir) + + program = 'posix_spawnp_test_program.exe' + program_fullpath = os.path.join(temp_dir, program) + os.symlink(sys.executable, program_fullpath) + + try: + path = os.pathsep.join((temp_dir, os.environ['PATH'])) + except KeyError: + path = temp_dir # PATH is not set + + spawn_args = (program, '-I', '-S', '-c', 'pass') + code = textwrap.dedent(""" + import os + args = %a + pid = os.posix_spawnp(args[0], args, os.environ) + pid2, status = os.waitpid(pid, 0) + if pid2 != pid: + raise Exception(f"pid {pid2} != {pid}") + if status != 0: + raise Exception(f"status {status} != 0") + """ % (spawn_args,)) + + # Use a subprocess to test os.posix_spawnp() with a modified PATH + # environment variable: posix_spawnp() uses the current environment + # to locate the program, not its environment argument. + args = ('-c', code) + assert_python_ok(*args, PATH=path) + + def test_main(): try: - support.run_unittest(PosixTester, PosixGroupsTester, TestPosixSpawn) + support.run_unittest( + PosixTester, + PosixGroupsTester, + TestPosixSpawn, + TestPosixSpawnP, + ) finally: support.reap_children() diff --git a/Misc/NEWS.d/next/Library/2019-01-14-14-13-08.bpo-35674.kamWqz.rst b/Misc/NEWS.d/next/Library/2019-01-14-14-13-08.bpo-35674.kamWqz.rst new file mode 100644 index 0000000..02d170e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-01-14-14-13-08.bpo-35674.kamWqz.rst @@ -0,0 +1,2 @@ +Add a new :func:`os.posix_spawnp` function. +Patch by Joannah Nanjekye. \ No newline at end of file diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 2c1ee97..ce17709 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -1791,6 +1791,75 @@ exit: #endif /* defined(HAVE_POSIX_SPAWN) */ +#if defined(HAVE_POSIX_SPAWNP) + +PyDoc_STRVAR(os_posix_spawnp__doc__, +"posix_spawnp($module, path, argv, env, /, *, file_actions=(),\n" +" setpgroup=None, resetids=False, setsigmask=(),\n" +" setsigdef=(), scheduler=None)\n" +"--\n" +"\n" +"Execute the program specified by path in a new process.\n" +"\n" +" path\n" +" Path of executable file.\n" +" argv\n" +" Tuple or list of strings.\n" +" env\n" +" Dictionary of strings mapping to strings.\n" +" file_actions\n" +" A sequence of file action tuples.\n" +" setpgroup\n" +" The pgroup to use with the POSIX_SPAWN_SETPGROUP flag.\n" +" resetids\n" +" If the value is `True` the POSIX_SPAWN_RESETIDS will be activated.\n" +" setsigmask\n" +" The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag.\n" +" setsigdef\n" +" The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag.\n" +" scheduler\n" +" A tuple with the scheduler policy (optional) and parameters."); + +#define OS_POSIX_SPAWNP_METHODDEF \ + {"posix_spawnp", (PyCFunction)(void(*)(void))os_posix_spawnp, METH_FASTCALL|METH_KEYWORDS, os_posix_spawnp__doc__}, + +static PyObject * +os_posix_spawnp_impl(PyObject *module, path_t *path, PyObject *argv, + PyObject *env, PyObject *file_actions, + PyObject *setpgroup, int resetids, PyObject *setsigmask, + PyObject *setsigdef, PyObject *scheduler); + +static PyObject * +os_posix_spawnp(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"", "", "", "file_actions", "setpgroup", "resetids", "setsigmask", "setsigdef", "scheduler", NULL}; + static _PyArg_Parser _parser = {"O&OO|$OOiOOO:posix_spawnp", _keywords, 0}; + path_t path = PATH_T_INITIALIZE("posix_spawnp", "path", 0, 0); + PyObject *argv; + PyObject *env; + PyObject *file_actions = NULL; + PyObject *setpgroup = NULL; + int resetids = 0; + PyObject *setsigmask = NULL; + PyObject *setsigdef = NULL; + PyObject *scheduler = NULL; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + path_converter, &path, &argv, &env, &file_actions, &setpgroup, &resetids, &setsigmask, &setsigdef, &scheduler)) { + goto exit; + } + return_value = os_posix_spawnp_impl(module, &path, argv, env, file_actions, setpgroup, resetids, setsigmask, setsigdef, scheduler); + +exit: + /* Cleanup for path */ + path_cleanup(&path); + + return return_value; +} + +#endif /* defined(HAVE_POSIX_SPAWNP) */ + #if (defined(HAVE_SPAWNV) || defined(HAVE_WSPAWNV)) PyDoc_STRVAR(os_spawnv__doc__, @@ -6851,6 +6920,10 @@ exit: #define OS_POSIX_SPAWN_METHODDEF #endif /* !defined(OS_POSIX_SPAWN_METHODDEF) */ +#ifndef OS_POSIX_SPAWNP_METHODDEF + #define OS_POSIX_SPAWNP_METHODDEF +#endif /* !defined(OS_POSIX_SPAWNP_METHODDEF) */ + #ifndef OS_SPAWNV_METHODDEF #define OS_SPAWNV_METHODDEF #endif /* !defined(OS_SPAWNV_METHODDEF) */ @@ -7258,4 +7331,4 @@ exit: #ifndef OS_GETRANDOM_METHODDEF #define OS_GETRANDOM_METHODDEF #endif /* !defined(OS_GETRANDOM_METHODDEF) */ -/*[clinic end generated code: output=febc1e16c9024e40 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=dabd0fa27bf87044 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index e5c2a9c..b25b522 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -5381,39 +5381,12 @@ fail: return -1; } -/*[clinic input] - -os.posix_spawn - path: path_t - Path of executable file. - argv: object - Tuple or list of strings. - env: object - Dictionary of strings mapping to strings. - / - * - file_actions: object(c_default='NULL') = () - A sequence of file action tuples. - setpgroup: object = NULL - The pgroup to use with the POSIX_SPAWN_SETPGROUP flag. - resetids: bool(accept={int}) = False - If the value is `True` the POSIX_SPAWN_RESETIDS will be activated. - setsigmask: object(c_default='NULL') = () - The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag. - setsigdef: object(c_default='NULL') = () - The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag. - scheduler: object = NULL - A tuple with the scheduler policy (optional) and parameters. - -Execute the program specified by path in a new process. -[clinic start generated code]*/ static PyObject * -os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv, - PyObject *env, PyObject *file_actions, - PyObject *setpgroup, int resetids, PyObject *setsigmask, - PyObject *setsigdef, PyObject *scheduler) -/*[clinic end generated code: output=45dfa4c515d09f2c input=2891c2f1d457e39b]*/ +py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *argv, + PyObject *env, PyObject *file_actions, + PyObject *setpgroup, int resetids, PyObject *setsigmask, + PyObject *setsigdef, PyObject *scheduler) { EXECV_CHAR **argvlist = NULL; EXECV_CHAR **envlist = NULL; @@ -5489,9 +5462,19 @@ os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv, attrp = &attr; _Py_BEGIN_SUPPRESS_IPH - err_code = posix_spawn(&pid, path->narrow, - file_actionsp, attrp, argvlist, envlist); +#ifdef HAVE_POSIX_SPAWNP + if (use_posix_spawnp) { + err_code = posix_spawnp(&pid, path->narrow, + file_actionsp, attrp, argvlist, envlist); + } + else +#endif /* HAVE_POSIX_SPAWNP */ + { + err_code = posix_spawn(&pid, path->narrow, + file_actionsp, attrp, argvlist, envlist); + } _Py_END_SUPPRESS_IPH + if (err_code) { errno = err_code; PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object); @@ -5518,7 +5501,90 @@ exit: Py_XDECREF(temp_buffer); return result; } -#endif /* HAVE_POSIX_SPAWN */ + + +/*[clinic input] + +os.posix_spawn + path: path_t + Path of executable file. + argv: object + Tuple or list of strings. + env: object + Dictionary of strings mapping to strings. + / + * + file_actions: object(c_default='NULL') = () + A sequence of file action tuples. + setpgroup: object = NULL + The pgroup to use with the POSIX_SPAWN_SETPGROUP flag. + resetids: bool(accept={int}) = False + If the value is `True` the POSIX_SPAWN_RESETIDS will be activated. + setsigmask: object(c_default='NULL') = () + The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag. + setsigdef: object(c_default='NULL') = () + The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag. + scheduler: object = NULL + A tuple with the scheduler policy (optional) and parameters. + +Execute the program specified by path in a new process. +[clinic start generated code]*/ + +static PyObject * +os_posix_spawn_impl(PyObject *module, path_t *path, PyObject *argv, + PyObject *env, PyObject *file_actions, + PyObject *setpgroup, int resetids, PyObject *setsigmask, + PyObject *setsigdef, PyObject *scheduler) +/*[clinic end generated code: output=45dfa4c515d09f2c input=2891c2f1d457e39b]*/ +{ + return py_posix_spawn(0, module, path, argv, env, file_actions, + setpgroup, resetids, setsigmask, setsigdef, + scheduler); +} + #endif /* HAVE_POSIX_SPAWN */ + + + +#ifdef HAVE_POSIX_SPAWNP +/*[clinic input] + +os.posix_spawnp + path: path_t + Path of executable file. + argv: object + Tuple or list of strings. + env: object + Dictionary of strings mapping to strings. + / + * + file_actions: object(c_default='NULL') = () + A sequence of file action tuples. + setpgroup: object = NULL + The pgroup to use with the POSIX_SPAWN_SETPGROUP flag. + resetids: bool(accept={int}) = False + If the value is `True` the POSIX_SPAWN_RESETIDS will be activated. + setsigmask: object(c_default='NULL') = () + The sigmask to use with the POSIX_SPAWN_SETSIGMASK flag. + setsigdef: object(c_default='NULL') = () + The sigmask to use with the POSIX_SPAWN_SETSIGDEF flag. + scheduler: object = NULL + A tuple with the scheduler policy (optional) and parameters. + +Execute the program specified by path in a new process. +[clinic start generated code]*/ + +static PyObject * +os_posix_spawnp_impl(PyObject *module, path_t *path, PyObject *argv, + PyObject *env, PyObject *file_actions, + PyObject *setpgroup, int resetids, PyObject *setsigmask, + PyObject *setsigdef, PyObject *scheduler) +/*[clinic end generated code: output=7955dc0edc82b8c3 input=b7576eb25b1ed9eb]*/ +{ + return py_posix_spawn(1, module, path, argv, env, file_actions, + setpgroup, resetids, setsigmask, setsigdef, + scheduler); +} +#endif /* HAVE_POSIX_SPAWNP */ #if defined(HAVE_SPAWNV) || defined(HAVE_WSPAWNV) @@ -13084,6 +13150,7 @@ static PyMethodDef posix_methods[] = { OS_GETPRIORITY_METHODDEF OS_SETPRIORITY_METHODDEF OS_POSIX_SPAWN_METHODDEF + OS_POSIX_SPAWNP_METHODDEF OS_READLINK_METHODDEF OS_RENAME_METHODDEF OS_REPLACE_METHODDEF diff --git a/aclocal.m4 b/aclocal.m4 index 94a2dd6..f98db73 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.15.1 -*- Autoconf -*- +# generated automatically by aclocal 1.15 -*- Autoconf -*- -# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -13,7 +13,7 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- -dnl serial 11 (pkg-config-0.29) +dnl serial 11 (pkg-config-0.29.1) dnl dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson @@ -55,7 +55,7 @@ dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], -[m4_define([PKG_MACROS_VERSION], [0.29]) +[m4_define([PKG_MACROS_VERSION], [0.29.1]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ diff --git a/configure b/configure index 13677b9..b32481d 100755 --- a/configure +++ b/configure @@ -11447,7 +11447,7 @@ for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \ initgroups kill killpg lchown lockf linkat lstat lutimes mmap \ memrchr mbrtowc mkdirat mkfifo \ mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \ - posix_fallocate posix_fadvise posix_spawn pread preadv preadv2 \ + posix_fallocate posix_fadvise posix_spawn posix_spawnp pread preadv preadv2 \ pthread_init pthread_kill putenv pwrite pwritev pwritev2 readlink readlinkat readv realpath renameat \ sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \ setgid sethostname \ diff --git a/configure.ac b/configure.ac index bd09a9c..262c726 100644 --- a/configure.ac +++ b/configure.ac @@ -3505,7 +3505,7 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \ initgroups kill killpg lchown lockf linkat lstat lutimes mmap \ memrchr mbrtowc mkdirat mkfifo \ mkfifoat mknod mknodat mktime mremap nice openat pathconf pause pipe2 plock poll \ - posix_fallocate posix_fadvise posix_spawn pread preadv preadv2 \ + posix_fallocate posix_fadvise posix_spawn posix_spawnp pread preadv preadv2 \ pthread_init pthread_kill putenv pwrite pwritev pwritev2 readlink readlinkat readv realpath renameat \ sem_open sem_timedwait sem_getvalue sem_unlink sendfile setegid seteuid \ setgid sethostname \ diff --git a/pyconfig.h.in b/pyconfig.h.in index f37ca36..a2a5623 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -732,6 +732,9 @@ /* Define to 1 if you have the `posix_spawn' function. */ #undef HAVE_POSIX_SPAWN +/* Define to 1 if you have the `posix_spawnp' function. */ +#undef HAVE_POSIX_SPAWNP + /* Define to 1 if you have the `pread' function. */ #undef HAVE_PREAD -- cgit v0.12