move sections
[python/dscho.git] / PC / _subprocess.c
blob6780382e6ea88cd3bcd2cb8610cf13c5aa1e564c
1 /*
2 * support routines for subprocess module
4 * Currently, this extension module is only required when using the
5 * subprocess module on Windows, but in the future, stubs for other
6 * platforms might be added here as well.
8 * Copyright (c) 2004 by Fredrik Lundh <fredrik@pythonware.com>
9 * Copyright (c) 2004 by Secret Labs AB, http://www.pythonware.com
10 * Copyright (c) 2004 by Peter Astrand <astrand@lysator.liu.se>
12 * By obtaining, using, and/or copying this software and/or its
13 * associated documentation, you agree that you have read, understood,
14 * and will comply with the following terms and conditions:
16 * Permission to use, copy, modify, and distribute this software and
17 * its associated documentation for any purpose and without fee is
18 * hereby granted, provided that the above copyright notice appears in
19 * all copies, and that both that copyright notice and this permission
20 * notice appear in supporting documentation, and that the name of the
21 * authors not be used in advertising or publicity pertaining to
22 * distribution of the software without specific, written prior
23 * permission.
25 * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
26 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
27 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
28 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
29 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
30 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
31 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35 /* Licensed to PSF under a Contributor Agreement. */
36 /* See http://www.python.org/2.4/license for licensing details. */
38 /* TODO: handle unicode command lines? */
39 /* TODO: handle unicode environment? */
41 #include "Python.h"
43 #define WINDOWS_LEAN_AND_MEAN
44 #include "windows.h"
46 /* -------------------------------------------------------------------- */
47 /* handle wrapper. note that this library uses integers when passing
48 handles to a function, and handle wrappers when returning handles.
49 the wrapper is used to provide Detach and Close methods */
51 typedef struct {
52 PyObject_HEAD
53 HANDLE handle;
54 } sp_handle_object;
56 staticforward PyTypeObject sp_handle_type;
58 static PyObject*
59 sp_handle_new(HANDLE handle)
61 sp_handle_object* self;
63 self = PyObject_NEW(sp_handle_object, &sp_handle_type);
64 if (self == NULL)
65 return NULL;
67 self->handle = handle;
69 return (PyObject*) self;
72 #if defined(MS_WIN32) && !defined(MS_WIN64)
73 #define HANDLE_TO_PYNUM(handle) PyInt_FromLong((long) handle)
74 #define PY_HANDLE_PARAM "l"
75 #else
76 #define HANDLE_TO_PYNUM(handle) PyLong_FromLongLong((long long) handle)
77 #define PY_HANDLE_PARAM "L"
78 #endif
80 static PyObject*
81 sp_handle_detach(sp_handle_object* self, PyObject* args)
83 HANDLE handle;
85 if (! PyArg_ParseTuple(args, ":Detach"))
86 return NULL;
88 handle = self->handle;
90 self->handle = INVALID_HANDLE_VALUE;
92 /* note: return the current handle, as an integer */
93 return HANDLE_TO_PYNUM(handle);
96 static PyObject*
97 sp_handle_close(sp_handle_object* self, PyObject* args)
99 if (! PyArg_ParseTuple(args, ":Close"))
100 return NULL;
102 if (self->handle != INVALID_HANDLE_VALUE) {
103 CloseHandle(self->handle);
104 self->handle = INVALID_HANDLE_VALUE;
106 Py_INCREF(Py_None);
107 return Py_None;
110 static void
111 sp_handle_dealloc(sp_handle_object* self)
113 if (self->handle != INVALID_HANDLE_VALUE)
114 CloseHandle(self->handle);
115 PyObject_FREE(self);
118 static PyMethodDef sp_handle_methods[] = {
119 {"Detach", (PyCFunction) sp_handle_detach, METH_VARARGS},
120 {"Close", (PyCFunction) sp_handle_close, METH_VARARGS},
121 {NULL, NULL}
124 static PyObject*
125 sp_handle_getattr(sp_handle_object* self, char* name)
127 return Py_FindMethod(sp_handle_methods, (PyObject*) self, name);
130 static PyObject*
131 sp_handle_as_int(sp_handle_object* self)
133 return HANDLE_TO_PYNUM(self->handle);
136 static PyNumberMethods sp_handle_as_number;
138 statichere PyTypeObject sp_handle_type = {
139 PyObject_HEAD_INIT(NULL)
140 0, /*ob_size*/
141 "_subprocess_handle", sizeof(sp_handle_object), 0,
142 (destructor) sp_handle_dealloc, /*tp_dealloc*/
143 0, /*tp_print*/
144 (getattrfunc) sp_handle_getattr,/*tp_getattr*/
145 0, /*tp_setattr*/
146 0, /*tp_compare*/
147 0, /*tp_repr*/
148 &sp_handle_as_number, /*tp_as_number */
149 0, /*tp_as_sequence */
150 0, /*tp_as_mapping */
151 0 /*tp_hash*/
154 /* -------------------------------------------------------------------- */
155 /* windows API functions */
157 PyDoc_STRVAR(GetStdHandle_doc,
158 "GetStdHandle(handle) -> integer\n\
160 Return a handle to the specified standard device\n\
161 (STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE).\n\
162 The integer associated with the handle object is returned.");
164 static PyObject *
165 sp_GetStdHandle(PyObject* self, PyObject* args)
167 HANDLE handle;
168 int std_handle;
170 if (! PyArg_ParseTuple(args, "i:GetStdHandle", &std_handle))
171 return NULL;
173 Py_BEGIN_ALLOW_THREADS
174 handle = GetStdHandle((DWORD) std_handle);
175 Py_END_ALLOW_THREADS
177 if (handle == INVALID_HANDLE_VALUE)
178 return PyErr_SetFromWindowsErr(GetLastError());
180 if (! handle) {
181 Py_INCREF(Py_None);
182 return Py_None;
185 /* note: returns integer, not handle object */
186 return HANDLE_TO_PYNUM(handle);
189 PyDoc_STRVAR(GetCurrentProcess_doc,
190 "GetCurrentProcess() -> handle\n\
192 Return a handle object for the current process.");
194 static PyObject *
195 sp_GetCurrentProcess(PyObject* self, PyObject* args)
197 if (! PyArg_ParseTuple(args, ":GetCurrentProcess"))
198 return NULL;
200 return sp_handle_new(GetCurrentProcess());
203 PyDoc_STRVAR(DuplicateHandle_doc,
204 "DuplicateHandle(source_proc_handle, source_handle,\n\
205 target_proc_handle, target_handle, access,\n\
206 inherit[, options]) -> handle\n\
208 Return a duplicate handle object.\n\
210 The duplicate handle refers to the same object as the original\n\
211 handle. Therefore, any changes to the object are reflected\n\
212 through both handles.");
214 static PyObject *
215 sp_DuplicateHandle(PyObject* self, PyObject* args)
217 HANDLE target_handle;
218 BOOL result;
220 HANDLE source_process_handle;
221 HANDLE source_handle;
222 HANDLE target_process_handle;
223 int desired_access;
224 int inherit_handle;
225 int options = 0;
227 if (! PyArg_ParseTuple(args,
228 PY_HANDLE_PARAM PY_HANDLE_PARAM PY_HANDLE_PARAM
229 "ii|i:DuplicateHandle",
230 &source_process_handle,
231 &source_handle,
232 &target_process_handle,
233 &desired_access,
234 &inherit_handle,
235 &options))
236 return NULL;
238 Py_BEGIN_ALLOW_THREADS
239 result = DuplicateHandle(
240 source_process_handle,
241 source_handle,
242 target_process_handle,
243 &target_handle,
244 desired_access,
245 inherit_handle,
246 options
248 Py_END_ALLOW_THREADS
250 if (! result)
251 return PyErr_SetFromWindowsErr(GetLastError());
253 return sp_handle_new(target_handle);
256 PyDoc_STRVAR(CreatePipe_doc,
257 "CreatePipe(pipe_attrs, size) -> (read_handle, write_handle)\n\
259 Create an anonymous pipe, and return handles to the read and\n\
260 write ends of the pipe.\n\
262 pipe_attrs is ignored internally and can be None.");
264 static PyObject *
265 sp_CreatePipe(PyObject* self, PyObject* args)
267 HANDLE read_pipe;
268 HANDLE write_pipe;
269 BOOL result;
271 PyObject* pipe_attributes; /* ignored */
272 int size;
274 if (! PyArg_ParseTuple(args, "Oi:CreatePipe", &pipe_attributes, &size))
275 return NULL;
277 Py_BEGIN_ALLOW_THREADS
278 result = CreatePipe(&read_pipe, &write_pipe, NULL, size);
279 Py_END_ALLOW_THREADS
281 if (! result)
282 return PyErr_SetFromWindowsErr(GetLastError());
284 return Py_BuildValue(
285 "NN", sp_handle_new(read_pipe), sp_handle_new(write_pipe));
288 /* helpers for createprocess */
290 static int
291 getint(PyObject* obj, char* name)
293 PyObject* value;
294 int ret;
296 value = PyObject_GetAttrString(obj, name);
297 if (! value) {
298 PyErr_Clear(); /* FIXME: propagate error? */
299 return 0;
301 ret = (int) PyInt_AsLong(value);
302 Py_DECREF(value);
303 return ret;
306 static HANDLE
307 gethandle(PyObject* obj, char* name)
309 sp_handle_object* value;
310 HANDLE ret;
312 value = (sp_handle_object*) PyObject_GetAttrString(obj, name);
313 if (! value) {
314 PyErr_Clear(); /* FIXME: propagate error? */
315 return NULL;
317 if (value->ob_type != &sp_handle_type)
318 ret = NULL;
319 else
320 ret = value->handle;
321 Py_DECREF(value);
322 return ret;
325 static PyObject*
326 getenvironment(PyObject* environment)
328 int i, envsize;
329 PyObject* out = NULL;
330 PyObject* keys;
331 PyObject* values;
332 char* p;
334 /* convert environment dictionary to windows enviroment string */
335 if (! PyMapping_Check(environment)) {
336 PyErr_SetString(
337 PyExc_TypeError, "environment must be dictionary or None");
338 return NULL;
341 envsize = PyMapping_Length(environment);
343 keys = PyMapping_Keys(environment);
344 values = PyMapping_Values(environment);
345 if (!keys || !values)
346 goto error;
348 out = PyString_FromStringAndSize(NULL, 2048);
349 if (! out)
350 goto error;
352 p = PyString_AS_STRING(out);
354 for (i = 0; i < envsize; i++) {
355 int ksize, vsize, totalsize;
356 PyObject* key = PyList_GET_ITEM(keys, i);
357 PyObject* value = PyList_GET_ITEM(values, i);
359 if (! PyString_Check(key) || ! PyString_Check(value)) {
360 PyErr_SetString(PyExc_TypeError,
361 "environment can only contain strings");
362 goto error;
364 ksize = PyString_GET_SIZE(key);
365 vsize = PyString_GET_SIZE(value);
366 totalsize = (p - PyString_AS_STRING(out)) + ksize + 1 +
367 vsize + 1 + 1;
368 if (totalsize > PyString_GET_SIZE(out)) {
369 int offset = p - PyString_AS_STRING(out);
370 _PyString_Resize(&out, totalsize + 1024);
371 p = PyString_AS_STRING(out) + offset;
373 memcpy(p, PyString_AS_STRING(key), ksize);
374 p += ksize;
375 *p++ = '=';
376 memcpy(p, PyString_AS_STRING(value), vsize);
377 p += vsize;
378 *p++ = '\0';
381 /* add trailing null byte */
382 *p++ = '\0';
383 _PyString_Resize(&out, p - PyString_AS_STRING(out));
385 /* PyObject_Print(out, stdout, 0); */
387 Py_XDECREF(keys);
388 Py_XDECREF(values);
390 return out;
392 error:
393 Py_XDECREF(out);
394 Py_XDECREF(keys);
395 Py_XDECREF(values);
396 return NULL;
399 PyDoc_STRVAR(CreateProcess_doc,
400 "CreateProcess(app_name, cmd_line, proc_attrs, thread_attrs,\n\
401 inherit, flags, env_mapping, curdir,\n\
402 startup_info) -> (proc_handle, thread_handle,\n\
403 pid, tid)\n\
405 Create a new process and its primary thread. The return\n\
406 value is a tuple of the process handle, thread handle,\n\
407 process ID, and thread ID.\n\
409 proc_attrs and thread_attrs are ignored internally and can be None.");
411 static PyObject *
412 sp_CreateProcess(PyObject* self, PyObject* args)
414 BOOL result;
415 PROCESS_INFORMATION pi;
416 STARTUPINFO si;
417 PyObject* environment;
419 char* application_name;
420 char* command_line;
421 PyObject* process_attributes; /* ignored */
422 PyObject* thread_attributes; /* ignored */
423 int inherit_handles;
424 int creation_flags;
425 PyObject* env_mapping;
426 char* current_directory;
427 PyObject* startup_info;
429 if (! PyArg_ParseTuple(args, "zzOOiiOzO:CreateProcess",
430 &application_name,
431 &command_line,
432 &process_attributes,
433 &thread_attributes,
434 &inherit_handles,
435 &creation_flags,
436 &env_mapping,
437 &current_directory,
438 &startup_info))
439 return NULL;
441 ZeroMemory(&si, sizeof(si));
442 si.cb = sizeof(si);
444 /* note: we only support a small subset of all SI attributes */
445 si.dwFlags = getint(startup_info, "dwFlags");
446 si.wShowWindow = getint(startup_info, "wShowWindow");
447 si.hStdInput = gethandle(startup_info, "hStdInput");
448 si.hStdOutput = gethandle(startup_info, "hStdOutput");
449 si.hStdError = gethandle(startup_info, "hStdError");
451 if (PyErr_Occurred())
452 return NULL;
454 if (env_mapping == Py_None)
455 environment = NULL;
456 else {
457 environment = getenvironment(env_mapping);
458 if (! environment)
459 return NULL;
462 Py_BEGIN_ALLOW_THREADS
463 result = CreateProcess(application_name,
464 command_line,
465 NULL,
466 NULL,
467 inherit_handles,
468 creation_flags,
469 environment ? PyString_AS_STRING(environment) : NULL,
470 current_directory,
471 &si,
472 &pi);
473 Py_END_ALLOW_THREADS
475 Py_XDECREF(environment);
477 if (! result)
478 return PyErr_SetFromWindowsErr(GetLastError());
480 return Py_BuildValue("NNii",
481 sp_handle_new(pi.hProcess),
482 sp_handle_new(pi.hThread),
483 pi.dwProcessId,
484 pi.dwThreadId);
487 PyDoc_STRVAR(TerminateProcess_doc,
488 "TerminateProcess(handle, exit_code) -> None\n\
490 Terminate the specified process and all of its threads.");
492 static PyObject *
493 sp_TerminateProcess(PyObject* self, PyObject* args)
495 BOOL result;
497 HANDLE process;
498 int exit_code;
499 if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM "i:TerminateProcess",
500 &process, &exit_code))
501 return NULL;
503 result = TerminateProcess(process, exit_code);
505 if (! result)
506 return PyErr_SetFromWindowsErr(GetLastError());
508 Py_INCREF(Py_None);
509 return Py_None;
512 PyDoc_STRVAR(GetExitCodeProcess_doc,
513 "GetExitCodeProcess(handle) -> Exit code\n\
515 Return the termination status of the specified process.");
517 static PyObject *
518 sp_GetExitCodeProcess(PyObject* self, PyObject* args)
520 DWORD exit_code;
521 BOOL result;
523 HANDLE process;
524 if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM ":GetExitCodeProcess", &process))
525 return NULL;
527 result = GetExitCodeProcess(process, &exit_code);
529 if (! result)
530 return PyErr_SetFromWindowsErr(GetLastError());
532 return PyInt_FromLong(exit_code);
535 PyDoc_STRVAR(WaitForSingleObject_doc,
536 "WaitForSingleObject(handle, timeout) -> result\n\
538 Wait until the specified object is in the signaled state or\n\
539 the time-out interval elapses. The timeout value is specified\n\
540 in milliseconds.");
542 static PyObject *
543 sp_WaitForSingleObject(PyObject* self, PyObject* args)
545 DWORD result;
547 HANDLE handle;
548 int milliseconds;
549 if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM "i:WaitForSingleObject",
550 &handle,
551 &milliseconds))
552 return NULL;
554 Py_BEGIN_ALLOW_THREADS
555 result = WaitForSingleObject(handle, (DWORD) milliseconds);
556 Py_END_ALLOW_THREADS
558 if (result == WAIT_FAILED)
559 return PyErr_SetFromWindowsErr(GetLastError());
561 return PyInt_FromLong((int) result);
564 PyDoc_STRVAR(GetVersion_doc,
565 "GetVersion() -> version\n\
567 Return the version number of the current operating system.");
569 static PyObject *
570 sp_GetVersion(PyObject* self, PyObject* args)
572 if (! PyArg_ParseTuple(args, ":GetVersion"))
573 return NULL;
575 return PyInt_FromLong((int) GetVersion());
578 PyDoc_STRVAR(GetModuleFileName_doc,
579 "GetModuleFileName(module) -> path\n\
581 Return the fully-qualified path for the file that contains\n\
582 the specified module. The module must have been loaded by the\n\
583 current process.\n\
585 The module parameter should be a handle to the loaded module\n\
586 whose path is being requested. If this parameter is 0, \n\
587 GetModuleFileName retrieves the path of the executable file\n\
588 of the current process.");
590 static PyObject *
591 sp_GetModuleFileName(PyObject* self, PyObject* args)
593 BOOL result;
594 HMODULE module;
595 TCHAR filename[MAX_PATH];
597 if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM ":GetModuleFileName",
598 &module))
599 return NULL;
601 result = GetModuleFileName(module, filename, MAX_PATH);
602 filename[MAX_PATH-1] = '\0';
604 if (! result)
605 return PyErr_SetFromWindowsErr(GetLastError());
607 return PyString_FromString(filename);
610 static PyMethodDef sp_functions[] = {
611 {"GetStdHandle", sp_GetStdHandle, METH_VARARGS, GetStdHandle_doc},
612 {"GetCurrentProcess", sp_GetCurrentProcess, METH_VARARGS,
613 GetCurrentProcess_doc},
614 {"DuplicateHandle", sp_DuplicateHandle, METH_VARARGS,
615 DuplicateHandle_doc},
616 {"CreatePipe", sp_CreatePipe, METH_VARARGS, CreatePipe_doc},
617 {"CreateProcess", sp_CreateProcess, METH_VARARGS, CreateProcess_doc},
618 {"TerminateProcess", sp_TerminateProcess, METH_VARARGS,
619 TerminateProcess_doc},
620 {"GetExitCodeProcess", sp_GetExitCodeProcess, METH_VARARGS,
621 GetExitCodeProcess_doc},
622 {"WaitForSingleObject", sp_WaitForSingleObject, METH_VARARGS,
623 WaitForSingleObject_doc},
624 {"GetVersion", sp_GetVersion, METH_VARARGS, GetVersion_doc},
625 {"GetModuleFileName", sp_GetModuleFileName, METH_VARARGS,
626 GetModuleFileName_doc},
627 {NULL, NULL}
630 /* -------------------------------------------------------------------- */
632 static void
633 defint(PyObject* d, const char* name, int value)
635 PyObject* v = PyInt_FromLong((long) value);
636 if (v) {
637 PyDict_SetItemString(d, (char*) name, v);
638 Py_DECREF(v);
642 #if PY_VERSION_HEX >= 0x02030000
643 PyMODINIT_FUNC
644 #else
645 DL_EXPORT(void)
646 #endif
647 init_subprocess()
649 PyObject *d;
650 PyObject *m;
652 /* patch up object descriptors */
653 sp_handle_type.ob_type = &PyType_Type;
654 sp_handle_as_number.nb_int = (unaryfunc) sp_handle_as_int;
656 m = Py_InitModule("_subprocess", sp_functions);
657 if (m == NULL)
658 return;
659 d = PyModule_GetDict(m);
661 /* constants */
662 defint(d, "STD_INPUT_HANDLE", STD_INPUT_HANDLE);
663 defint(d, "STD_OUTPUT_HANDLE", STD_OUTPUT_HANDLE);
664 defint(d, "STD_ERROR_HANDLE", STD_ERROR_HANDLE);
665 defint(d, "DUPLICATE_SAME_ACCESS", DUPLICATE_SAME_ACCESS);
666 defint(d, "STARTF_USESTDHANDLES", STARTF_USESTDHANDLES);
667 defint(d, "STARTF_USESHOWWINDOW", STARTF_USESHOWWINDOW);
668 defint(d, "SW_HIDE", SW_HIDE);
669 defint(d, "INFINITE", INFINITE);
670 defint(d, "WAIT_OBJECT_0", WAIT_OBJECT_0);
671 defint(d, "CREATE_NEW_CONSOLE", CREATE_NEW_CONSOLE);
672 defint(d, "CREATE_NEW_PROCESS_GROUP", CREATE_NEW_PROCESS_GROUP);