blob: 15c3dc4d1b945697ed64a98158dea2166b8dbcc0 [file] [log] [blame]
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +00001/* Authors: Gregory P. Smith & Jeffrey Yasskin */
2#include "Python.h"
3#include <unistd.h>
4
5
6#define POSIX_CALL(call) if ((call) == -1) goto error
7
8
9/* Maximum file descriptor, initialized on module load. */
10static long max_fd;
11
12
13/* Given the gc module call gc.enable() and return 0 on success. */
14static int _enable_gc(PyObject *gc_module)
15{
16 PyObject *result;
17 result = PyObject_CallMethod(gc_module, "enable", NULL);
18 if (result == NULL)
19 return 1;
20 Py_DECREF(result);
21 return 0;
22}
23
24
25/*
26 * This function is code executed in the child process immediately after fork
27 * to set things up and call exec().
28 *
29 * All of the code in this function must only use async-signal-safe functions,
30 * listed at `man 7 signal` or
31 * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html.
32 *
33 * This restriction is documented at
34 * http://www.opengroup.org/onlinepubs/009695399/functions/fork.html.
35 */
36static void child_exec(char *const exec_array[],
37 char *const argv[],
38 char *const envp[],
39 const char *cwd,
40 int p2cread, int p2cwrite,
41 int c2pread, int c2pwrite,
42 int errread, int errwrite,
43 int errpipe_read, int errpipe_write,
44 int close_fds, int restore_signals,
45 int call_setsid,
46 PyObject *preexec_fn,
47 PyObject *preexec_fn_args_tuple)
48{
49 int i, saved_errno, fd_num;
50 PyObject *result;
51 const char* err_msg;
52 /* Buffer large enough to hold a hex integer. We can't malloc. */
53 char hex_errno[sizeof(saved_errno)*2+1];
54
55 /* Close parent's pipe ends. */
56 if (p2cwrite != -1) {
57 POSIX_CALL(close(p2cwrite));
58 }
59 if (c2pread != -1) {
60 POSIX_CALL(close(c2pread));
61 }
62 if (errread != -1) {
63 POSIX_CALL(close(errread));
64 }
65 POSIX_CALL(close(errpipe_read));
66
67 /* Dup fds for child. */
68 if (p2cread != -1) {
69 POSIX_CALL(dup2(p2cread, 0)); /* stdin */
70 }
71 if (c2pwrite != -1) {
72 POSIX_CALL(dup2(c2pwrite, 1)); /* stdout */
73 }
74 if (errwrite != -1) {
75 POSIX_CALL(dup2(errwrite, 2)); /* stderr */
76 }
77
78 /* Close pipe fds. Make sure we don't close the same fd more than */
79 /* once, or standard fds. */
80 if (p2cread != -1 && p2cread != 0) {
81 POSIX_CALL(close(p2cread));
82 }
83 if (c2pwrite != -1 && c2pwrite != p2cread && c2pwrite != 1) {
84 POSIX_CALL(close(c2pwrite));
85 }
86 if (errwrite != -1 && errwrite != p2cread &&
87 errwrite != c2pwrite && errwrite != 2) {
88 POSIX_CALL(close(errwrite));
89 }
90
91 /* close() is intentionally not checked for errors here as we are closing */
92 /* a large range of fds, some of which may be invalid. */
93 if (close_fds) {
94 for (fd_num = 3; fd_num < errpipe_write; ++fd_num) {
95 close(fd_num);
96 }
97 for (fd_num = errpipe_write+1; fd_num < max_fd; ++fd_num) {
98 close(fd_num);
99 }
100 }
101
102 if (cwd)
103 POSIX_CALL(chdir(cwd));
104
105 if (restore_signals)
106 _Py_RestoreSignals();
107
108#ifdef HAVE_SETSID
109 if (call_setsid)
110 POSIX_CALL(setsid());
111#endif
112
113 if (preexec_fn != Py_None && preexec_fn_args_tuple) {
114 /* This is where the user has asked us to deadlock their program. */
115 result = PyObject_Call(preexec_fn, preexec_fn_args_tuple, NULL);
116 if (result == NULL) {
117 /* Stringifying the exception or traceback would involve
118 * memory allocation and thus potential for deadlock.
119 * We've already faced potential deadlock by calling back
120 * into Python in the first place, so it probably doesn't
121 * matter but we avoid it to minimize the possibility. */
122 err_msg = "Exception occurred in preexec_fn.";
123 errno = 0; /* We don't want to report an OSError. */
124 goto error;
125 }
126 /* Py_DECREF(result); - We're about to exec so why bother? */
127 }
128
129 /* This loop matches the Lib/os.py _execvpe()'s PATH search when */
130 /* given the executable_list generated by Lib/subprocess.py. */
131 saved_errno = 0;
132 for (i = 0; exec_array[i] != NULL; ++i) {
133 const char *executable = exec_array[i];
134 if (envp) {
135 execve(executable, argv, envp);
136 } else {
137 execv(executable, argv);
138 }
139 if (errno != ENOENT && errno != ENOTDIR && saved_errno == 0) {
140 saved_errno = errno;
141 }
142 }
143 /* Report the first exec error, not the last. */
144 if (saved_errno)
145 errno = saved_errno;
146
147error:
148 saved_errno = errno;
149 /* Report the posix error to our parent process. */
150 if (saved_errno) {
151 char *cur;
152 write(errpipe_write, "OSError:", 8);
153 cur = hex_errno + sizeof(hex_errno);
154 while (saved_errno != 0 && cur > hex_errno) {
155 *--cur = "0123456789ABCDEF"[saved_errno % 16];
156 saved_errno /= 16;
157 }
158 write(errpipe_write, cur, hex_errno + sizeof(hex_errno) - cur);
159 write(errpipe_write, ":", 1);
160 /* We can't call strerror(saved_errno). It is not async signal safe.
161 * The parent process will look the error message up. */
162 } else {
163 write(errpipe_write, "RuntimeError:0:", 15);
164 write(errpipe_write, err_msg, strlen(err_msg));
165 }
166}
167
168
169static PyObject *
170subprocess_fork_exec(PyObject* self, PyObject *args)
171{
172 PyObject *gc_module = NULL;
173 PyObject *executable_list, *py_close_fds;
174 PyObject *env_list, *preexec_fn;
Gregory P. Smith68f52172010-03-15 06:07:42 +0000175 PyObject *process_args, *converted_args = NULL, *fast_args = NULL;
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000176 PyObject *preexec_fn_args_tuple = NULL;
177 int p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite;
178 int errpipe_read, errpipe_write, close_fds, restore_signals;
179 int call_setsid;
Victor Stinner0e59cc32010-04-16 23:49:32 +0000180 PyObject *cwd_obj, *cwd_obj2;
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000181 const char *cwd;
182 pid_t pid;
183 int need_to_reenable_gc = 0;
184 char *const *exec_array, *const *argv = NULL, *const *envp = NULL;
185 Py_ssize_t arg_num;
186
187 if (!PyArg_ParseTuple(
Victor Stinner0e59cc32010-04-16 23:49:32 +0000188 args, "OOOOOiiiiiiiiiiO:fork_exec",
189 &process_args, &executable_list, &py_close_fds,
190 &cwd_obj, &env_list,
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000191 &p2cread, &p2cwrite, &c2pread, &c2pwrite,
192 &errread, &errwrite, &errpipe_read, &errpipe_write,
193 &restore_signals, &call_setsid, &preexec_fn))
194 return NULL;
195
196 close_fds = PyObject_IsTrue(py_close_fds);
197 if (close_fds && errpipe_write < 3) { /* precondition */
198 PyErr_SetString(PyExc_ValueError, "errpipe_write must be >= 3");
199 return NULL;
200 }
201
202 /* We need to call gc.disable() when we'll be calling preexec_fn */
203 if (preexec_fn != Py_None) {
204 PyObject *result;
205 gc_module = PyImport_ImportModule("gc");
206 if (gc_module == NULL)
207 return NULL;
208 result = PyObject_CallMethod(gc_module, "isenabled", NULL);
Gregory P. Smith32ec9da2010-03-19 16:53:08 +0000209 if (result == NULL) {
210 Py_DECREF(gc_module);
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000211 return NULL;
Gregory P. Smith32ec9da2010-03-19 16:53:08 +0000212 }
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000213 need_to_reenable_gc = PyObject_IsTrue(result);
214 Py_DECREF(result);
Gregory P. Smith32ec9da2010-03-19 16:53:08 +0000215 if (need_to_reenable_gc == -1) {
216 Py_DECREF(gc_module);
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000217 return NULL;
Gregory P. Smith32ec9da2010-03-19 16:53:08 +0000218 }
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000219 result = PyObject_CallMethod(gc_module, "disable", NULL);
Gregory P. Smith32ec9da2010-03-19 16:53:08 +0000220 if (result == NULL) {
221 Py_DECREF(gc_module);
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000222 return NULL;
Gregory P. Smith32ec9da2010-03-19 16:53:08 +0000223 }
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000224 Py_DECREF(result);
225 }
226
227 exec_array = _PySequence_BytesToCharpArray(executable_list);
228 if (!exec_array)
229 return NULL;
230
231 /* Convert args and env into appropriate arguments for exec() */
232 /* These conversions are done in the parent process to avoid allocating
233 or freeing memory in the child process. */
234 if (process_args != Py_None) {
Gregory P. Smith68f52172010-03-15 06:07:42 +0000235 Py_ssize_t num_args;
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000236 /* Equivalent to: */
237 /* tuple(PyUnicode_FSConverter(arg) for arg in process_args) */
Gregory P. Smith68f52172010-03-15 06:07:42 +0000238 fast_args = PySequence_Fast(process_args, "argv must be a tuple");
239 num_args = PySequence_Fast_GET_SIZE(fast_args);
240 converted_args = PyTuple_New(num_args);
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000241 if (converted_args == NULL)
242 goto cleanup;
Gregory P. Smith68f52172010-03-15 06:07:42 +0000243 for (arg_num = 0; arg_num < num_args; ++arg_num) {
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000244 PyObject *borrowed_arg, *converted_arg;
Gregory P. Smith68f52172010-03-15 06:07:42 +0000245 borrowed_arg = PySequence_Fast_GET_ITEM(fast_args, arg_num);
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000246 if (PyUnicode_FSConverter(borrowed_arg, &converted_arg) == 0)
247 goto cleanup;
248 PyTuple_SET_ITEM(converted_args, arg_num, converted_arg);
249 }
250
251 argv = _PySequence_BytesToCharpArray(converted_args);
252 Py_CLEAR(converted_args);
Gregory P. Smith68f52172010-03-15 06:07:42 +0000253 Py_CLEAR(fast_args);
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000254 if (!argv)
255 goto cleanup;
256 }
257
258 if (env_list != Py_None) {
259 envp = _PySequence_BytesToCharpArray(env_list);
260 if (!envp)
261 goto cleanup;
262 }
263
264 if (preexec_fn != Py_None) {
265 preexec_fn_args_tuple = PyTuple_New(0);
266 if (!preexec_fn_args_tuple)
267 goto cleanup;
Victor Stinner0e59cc32010-04-16 23:49:32 +0000268 _PyImport_AcquireLock();
269 }
270
271 if (cwd_obj != Py_None) {
272 if (PyUnicode_FSConverter(cwd_obj, &cwd_obj2) == 0)
273 goto cleanup;
Victor Stinnerdcb24032010-04-22 12:08:36 +0000274 cwd = PyBytes_AsString(cwd_obj2);
Victor Stinner0e59cc32010-04-16 23:49:32 +0000275 } else {
276 cwd = NULL;
277 cwd_obj2 = NULL;
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000278 }
279
280 pid = fork();
281 if (pid == 0) {
282 /* Child process */
Victor Stinner0e59cc32010-04-16 23:49:32 +0000283 /*
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000284 * Code from here to _exit() must only use async-signal-safe functions,
285 * listed at `man 7 signal` or
286 * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html.
287 */
288
289 if (preexec_fn != Py_None) {
290 /* We'll be calling back into Python later so we need to do this.
291 * This call may not be async-signal-safe but neither is calling
292 * back into Python. The user asked us to use hope as a strategy
293 * to avoid deadlock... */
294 PyOS_AfterFork();
295 }
296
297 child_exec(exec_array, argv, envp, cwd,
298 p2cread, p2cwrite, c2pread, c2pwrite,
299 errread, errwrite, errpipe_read, errpipe_write,
300 close_fds, restore_signals, call_setsid,
301 preexec_fn, preexec_fn_args_tuple);
302 _exit(255);
303 return NULL; /* Dead code to avoid a potential compiler warning. */
304 }
Victor Stinner0e59cc32010-04-16 23:49:32 +0000305 Py_XDECREF(cwd_obj2);
306
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000307 if (pid == -1) {
308 /* Capture the errno exception before errno can be clobbered. */
309 PyErr_SetFromErrno(PyExc_OSError);
310 }
311 if (preexec_fn != Py_None &&
312 _PyImport_ReleaseLock() < 0 && !PyErr_Occurred()) {
313 PyErr_SetString(PyExc_RuntimeError,
314 "not holding the import lock");
315 }
316
317 /* Parent process */
318 if (envp)
319 _Py_FreeCharPArray(envp);
320 if (argv)
321 _Py_FreeCharPArray(argv);
322 _Py_FreeCharPArray(exec_array);
323
324 /* Reenable gc in the parent process (or if fork failed). */
325 if (need_to_reenable_gc && _enable_gc(gc_module)) {
326 Py_XDECREF(gc_module);
327 return NULL;
328 }
Gregory P. Smith32ec9da2010-03-19 16:53:08 +0000329 Py_XDECREF(preexec_fn_args_tuple);
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000330 Py_XDECREF(gc_module);
331
332 if (pid == -1)
333 return NULL; /* fork() failed. Exception set earlier. */
334
335 return PyLong_FromPid(pid);
336
337cleanup:
338 if (envp)
339 _Py_FreeCharPArray(envp);
340 if (argv)
341 _Py_FreeCharPArray(argv);
342 _Py_FreeCharPArray(exec_array);
343 Py_XDECREF(converted_args);
Gregory P. Smith68f52172010-03-15 06:07:42 +0000344 Py_XDECREF(fast_args);
Gregory P. Smith32ec9da2010-03-19 16:53:08 +0000345 Py_XDECREF(preexec_fn_args_tuple);
Gregory P. Smithfb94c5f2010-03-14 06:49:55 +0000346
347 /* Reenable gc if it was disabled. */
348 if (need_to_reenable_gc)
349 _enable_gc(gc_module);
350 Py_XDECREF(gc_module);
351 return NULL;
352}
353
354
355PyDoc_STRVAR(subprocess_fork_exec_doc,
356"fork_exec(args, executable_list, close_fds, cwd, env,\n\
357 p2cread, p2cwrite, c2pread, c2pwrite,\n\
358 errread, errwrite, errpipe_read, errpipe_write,\n\
359 restore_signals, call_setsid, preexec_fn)\n\
360\n\
361Forks a child process, closes parent file descriptors as appropriate in the\n\
362child and dups the few that are needed before calling exec() in the child\n\
363process.\n\
364\n\
365The preexec_fn, if supplied, will be called immediately before exec.\n\
366WARNING: preexec_fn is NOT SAFE if your application uses threads.\n\
367 It may trigger infrequent, difficult to debug deadlocks.\n\
368\n\
369If an error occurs in the child process before the exec, it is\n\
370serialized and written to the errpipe_write fd per subprocess.py.\n\
371\n\
372Returns: the child process's PID.\n\
373\n\
374Raises: Only on an error in the parent process.\n\
375");
376
377
378/* module level code ********************************************************/
379
380PyDoc_STRVAR(module_doc,
381"A POSIX helper for the subprocess module.");
382
383
384static PyMethodDef module_methods[] = {
385 {"fork_exec", subprocess_fork_exec, METH_VARARGS, subprocess_fork_exec_doc},
386 {NULL, NULL} /* sentinel */
387};
388
389
390static struct PyModuleDef _posixsubprocessmodule = {
391 PyModuleDef_HEAD_INIT,
392 "_posixsubprocess",
393 module_doc,
394 -1, /* No memory is needed. */
395 module_methods,
396};
397
398PyMODINIT_FUNC
399PyInit__posixsubprocess(void)
400{
401#ifdef _SC_OPEN_MAX
402 max_fd = sysconf(_SC_OPEN_MAX);
403 if (max_fd == -1)
404#endif
405 max_fd = 256; /* Matches Lib/subprocess.py */
406
407 return PyModule_Create(&_posixsubprocessmodule);
408}