1 /* 2 * support routines for subprocess module 3 * 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. 7 * 8 * Copyright (c) 2004 by Fredrik Lundh <fredrik (at) pythonware.com> 9 * Copyright (c) 2004 by Secret Labs AB, http://www.pythonware.com 10 * Copyright (c) 2004 by Peter Astrand <astrand (at) lysator.liu.se> 11 * 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: 15 * 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. 24 * 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. 32 * 33 */ 34 35 /* Licensed to PSF under a Contributor Agreement. */ 36 /* See http://www.python.org/2.4/license for licensing details. */ 37 38 /* TODO: handle unicode command lines? */ 39 /* TODO: handle unicode environment? */ 40 41 #include "Python.h" 42 43 #define WINDOWS_LEAN_AND_MEAN 44 #include "windows.h" 45 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 */ 50 51 typedef struct { 52 PyObject_HEAD 53 HANDLE handle; 54 } sp_handle_object; 55 56 staticforward PyTypeObject sp_handle_type; 57 58 static PyObject* 59 sp_handle_new(HANDLE handle) 60 { 61 sp_handle_object* self; 62 63 self = PyObject_NEW(sp_handle_object, &sp_handle_type); 64 if (self == NULL) 65 return NULL; 66 67 self->handle = handle; 68 69 return (PyObject*) self; 70 } 71 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 79 80 static PyObject* 81 sp_handle_detach(sp_handle_object* self, PyObject* args) 82 { 83 HANDLE handle; 84 85 if (! PyArg_ParseTuple(args, ":Detach")) 86 return NULL; 87 88 handle = self->handle; 89 90 self->handle = INVALID_HANDLE_VALUE; 91 92 /* note: return the current handle, as an integer */ 93 return HANDLE_TO_PYNUM(handle); 94 } 95 96 static PyObject* 97 sp_handle_close(sp_handle_object* self, PyObject* args) 98 { 99 if (! PyArg_ParseTuple(args, ":Close")) 100 return NULL; 101 102 if (self->handle != INVALID_HANDLE_VALUE) { 103 CloseHandle(self->handle); 104 self->handle = INVALID_HANDLE_VALUE; 105 } 106 Py_INCREF(Py_None); 107 return Py_None; 108 } 109 110 static void 111 sp_handle_dealloc(sp_handle_object* self) 112 { 113 if (self->handle != INVALID_HANDLE_VALUE) 114 CloseHandle(self->handle); 115 PyObject_FREE(self); 116 } 117 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} 122 }; 123 124 static PyObject* 125 sp_handle_getattr(sp_handle_object* self, char* name) 126 { 127 return Py_FindMethod(sp_handle_methods, (PyObject*) self, name); 128 } 129 130 static PyObject* 131 sp_handle_as_int(sp_handle_object* self) 132 { 133 return HANDLE_TO_PYNUM(self->handle); 134 } 135 136 static PyNumberMethods sp_handle_as_number; 137 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*/ 152 }; 153 154 /* -------------------------------------------------------------------- */ 155 /* windows API functions */ 156 157 PyDoc_STRVAR(GetStdHandle_doc, 158 "GetStdHandle(handle) -> integer\n\ 159 \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."); 163 164 static PyObject * 165 sp_GetStdHandle(PyObject* self, PyObject* args) 166 { 167 HANDLE handle; 168 int std_handle; 169 170 if (! PyArg_ParseTuple(args, "i:GetStdHandle", &std_handle)) 171 return NULL; 172 173 Py_BEGIN_ALLOW_THREADS 174 handle = GetStdHandle((DWORD) std_handle); 175 Py_END_ALLOW_THREADS 176 177 if (handle == INVALID_HANDLE_VALUE) 178 return PyErr_SetFromWindowsErr(GetLastError()); 179 180 if (! handle) { 181 Py_INCREF(Py_None); 182 return Py_None; 183 } 184 185 /* note: returns integer, not handle object */ 186 return HANDLE_TO_PYNUM(handle); 187 } 188 189 PyDoc_STRVAR(GetCurrentProcess_doc, 190 "GetCurrentProcess() -> handle\n\ 191 \n\ 192 Return a handle object for the current process."); 193 194 static PyObject * 195 sp_GetCurrentProcess(PyObject* self, PyObject* args) 196 { 197 if (! PyArg_ParseTuple(args, ":GetCurrentProcess")) 198 return NULL; 199 200 return sp_handle_new(GetCurrentProcess()); 201 } 202 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\ 207 \n\ 208 Return a duplicate handle object.\n\ 209 \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."); 213 214 static PyObject * 215 sp_DuplicateHandle(PyObject* self, PyObject* args) 216 { 217 HANDLE target_handle; 218 BOOL result; 219 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; 226 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; 237 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 247 ); 248 Py_END_ALLOW_THREADS 249 250 if (! result) 251 return PyErr_SetFromWindowsErr(GetLastError()); 252 253 return sp_handle_new(target_handle); 254 } 255 256 PyDoc_STRVAR(CreatePipe_doc, 257 "CreatePipe(pipe_attrs, size) -> (read_handle, write_handle)\n\ 258 \n\ 259 Create an anonymous pipe, and return handles to the read and\n\ 260 write ends of the pipe.\n\ 261 \n\ 262 pipe_attrs is ignored internally and can be None."); 263 264 static PyObject * 265 sp_CreatePipe(PyObject* self, PyObject* args) 266 { 267 HANDLE read_pipe; 268 HANDLE write_pipe; 269 BOOL result; 270 271 PyObject* pipe_attributes; /* ignored */ 272 int size; 273 274 if (! PyArg_ParseTuple(args, "Oi:CreatePipe", &pipe_attributes, &size)) 275 return NULL; 276 277 Py_BEGIN_ALLOW_THREADS 278 result = CreatePipe(&read_pipe, &write_pipe, NULL, size); 279 Py_END_ALLOW_THREADS 280 281 if (! result) 282 return PyErr_SetFromWindowsErr(GetLastError()); 283 284 return Py_BuildValue( 285 "NN", sp_handle_new(read_pipe), sp_handle_new(write_pipe)); 286 } 287 288 /* helpers for createprocess */ 289 290 static int 291 getint(PyObject* obj, char* name) 292 { 293 PyObject* value; 294 int ret; 295 296 value = PyObject_GetAttrString(obj, name); 297 if (! value) { 298 PyErr_Clear(); /* FIXME: propagate error? */ 299 return 0; 300 } 301 ret = (int) PyInt_AsLong(value); 302 Py_DECREF(value); 303 return ret; 304 } 305 306 static HANDLE 307 gethandle(PyObject* obj, char* name) 308 { 309 sp_handle_object* value; 310 HANDLE ret; 311 312 value = (sp_handle_object*) PyObject_GetAttrString(obj, name); 313 if (! value) { 314 PyErr_Clear(); /* FIXME: propagate error? */ 315 return NULL; 316 } 317 if (value->ob_type != &sp_handle_type) 318 ret = NULL; 319 else 320 ret = value->handle; 321 Py_DECREF(value); 322 return ret; 323 } 324 325 static PyObject* 326 getenvironment(PyObject* environment) 327 { 328 int i, envsize; 329 PyObject* out = NULL; 330 PyObject* keys; 331 PyObject* values; 332 char* p; 333 334 /* convert environment dictionary to windows environment string */ 335 if (! PyMapping_Check(environment)) { 336 PyErr_SetString( 337 PyExc_TypeError, "environment must be dictionary or None"); 338 return NULL; 339 } 340 341 envsize = PyMapping_Length(environment); 342 343 keys = PyMapping_Keys(environment); 344 values = PyMapping_Values(environment); 345 if (!keys || !values) 346 goto error; 347 348 out = PyString_FromStringAndSize(NULL, 2048); 349 if (! out) 350 goto error; 351 352 p = PyString_AS_STRING(out); 353 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); 358 359 if (! PyString_Check(key) || ! PyString_Check(value)) { 360 PyErr_SetString(PyExc_TypeError, 361 "environment can only contain strings"); 362 goto error; 363 } 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 if (_PyString_Resize(&out, totalsize + 1024)) 371 goto exit; 372 p = PyString_AS_STRING(out) + offset; 373 } 374 memcpy(p, PyString_AS_STRING(key), ksize); 375 p += ksize; 376 *p++ = '='; 377 memcpy(p, PyString_AS_STRING(value), vsize); 378 p += vsize; 379 *p++ = '\0'; 380 } 381 382 /* add trailing null byte */ 383 *p++ = '\0'; 384 _PyString_Resize(&out, p - PyString_AS_STRING(out)); 385 386 /* PyObject_Print(out, stdout, 0); */ 387 exit: 388 Py_XDECREF(keys); 389 Py_XDECREF(values); 390 391 return out; 392 393 error: 394 Py_XDECREF(out); 395 Py_XDECREF(keys); 396 Py_XDECREF(values); 397 return NULL; 398 } 399 400 PyDoc_STRVAR(CreateProcess_doc, 401 "CreateProcess(app_name, cmd_line, proc_attrs, thread_attrs,\n\ 402 inherit, flags, env_mapping, curdir,\n\ 403 startup_info) -> (proc_handle, thread_handle,\n\ 404 pid, tid)\n\ 405 \n\ 406 Create a new process and its primary thread. The return\n\ 407 value is a tuple of the process handle, thread handle,\n\ 408 process ID, and thread ID.\n\ 409 \n\ 410 proc_attrs and thread_attrs are ignored internally and can be None."); 411 412 static PyObject * 413 sp_CreateProcess(PyObject* self, PyObject* args) 414 { 415 BOOL result; 416 PROCESS_INFORMATION pi; 417 STARTUPINFO si; 418 PyObject* environment; 419 420 char* application_name; 421 char* command_line; 422 PyObject* process_attributes; /* ignored */ 423 PyObject* thread_attributes; /* ignored */ 424 int inherit_handles; 425 int creation_flags; 426 PyObject* env_mapping; 427 char* current_directory; 428 PyObject* startup_info; 429 430 if (! PyArg_ParseTuple(args, "zzOOiiOzO:CreateProcess", 431 &application_name, 432 &command_line, 433 &process_attributes, 434 &thread_attributes, 435 &inherit_handles, 436 &creation_flags, 437 &env_mapping, 438 ¤t_directory, 439 &startup_info)) 440 return NULL; 441 442 ZeroMemory(&si, sizeof(si)); 443 si.cb = sizeof(si); 444 445 /* note: we only support a small subset of all SI attributes */ 446 si.dwFlags = getint(startup_info, "dwFlags"); 447 si.wShowWindow = getint(startup_info, "wShowWindow"); 448 si.hStdInput = gethandle(startup_info, "hStdInput"); 449 si.hStdOutput = gethandle(startup_info, "hStdOutput"); 450 si.hStdError = gethandle(startup_info, "hStdError"); 451 452 if (PyErr_Occurred()) 453 return NULL; 454 455 if (env_mapping == Py_None) 456 environment = NULL; 457 else { 458 environment = getenvironment(env_mapping); 459 if (! environment) 460 return NULL; 461 } 462 463 Py_BEGIN_ALLOW_THREADS 464 result = CreateProcess(application_name, 465 command_line, 466 NULL, 467 NULL, 468 inherit_handles, 469 creation_flags, 470 environment ? PyString_AS_STRING(environment) : NULL, 471 current_directory, 472 &si, 473 &pi); 474 Py_END_ALLOW_THREADS 475 476 Py_XDECREF(environment); 477 478 if (! result) 479 return PyErr_SetFromWindowsErr(GetLastError()); 480 481 return Py_BuildValue("NNii", 482 sp_handle_new(pi.hProcess), 483 sp_handle_new(pi.hThread), 484 pi.dwProcessId, 485 pi.dwThreadId); 486 } 487 488 PyDoc_STRVAR(TerminateProcess_doc, 489 "TerminateProcess(handle, exit_code) -> None\n\ 490 \n\ 491 Terminate the specified process and all of its threads."); 492 493 static PyObject * 494 sp_TerminateProcess(PyObject* self, PyObject* args) 495 { 496 BOOL result; 497 498 HANDLE process; 499 int exit_code; 500 if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM "i:TerminateProcess", 501 &process, &exit_code)) 502 return NULL; 503 504 result = TerminateProcess(process, exit_code); 505 506 if (! result) 507 return PyErr_SetFromWindowsErr(GetLastError()); 508 509 Py_INCREF(Py_None); 510 return Py_None; 511 } 512 513 PyDoc_STRVAR(GetExitCodeProcess_doc, 514 "GetExitCodeProcess(handle) -> Exit code\n\ 515 \n\ 516 Return the termination status of the specified process."); 517 518 static PyObject * 519 sp_GetExitCodeProcess(PyObject* self, PyObject* args) 520 { 521 DWORD exit_code; 522 BOOL result; 523 524 HANDLE process; 525 if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM ":GetExitCodeProcess", &process)) 526 return NULL; 527 528 result = GetExitCodeProcess(process, &exit_code); 529 530 if (! result) 531 return PyErr_SetFromWindowsErr(GetLastError()); 532 533 return PyInt_FromLong(exit_code); 534 } 535 536 PyDoc_STRVAR(WaitForSingleObject_doc, 537 "WaitForSingleObject(handle, timeout) -> result\n\ 538 \n\ 539 Wait until the specified object is in the signaled state or\n\ 540 the time-out interval elapses. The timeout value is specified\n\ 541 in milliseconds."); 542 543 static PyObject * 544 sp_WaitForSingleObject(PyObject* self, PyObject* args) 545 { 546 DWORD result; 547 548 HANDLE handle; 549 int milliseconds; 550 if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM "i:WaitForSingleObject", 551 &handle, 552 &milliseconds)) 553 return NULL; 554 555 Py_BEGIN_ALLOW_THREADS 556 result = WaitForSingleObject(handle, (DWORD) milliseconds); 557 Py_END_ALLOW_THREADS 558 559 if (result == WAIT_FAILED) 560 return PyErr_SetFromWindowsErr(GetLastError()); 561 562 return PyInt_FromLong((int) result); 563 } 564 565 PyDoc_STRVAR(GetVersion_doc, 566 "GetVersion() -> version\n\ 567 \n\ 568 Return the version number of the current operating system."); 569 570 static PyObject * 571 sp_GetVersion(PyObject* self, PyObject* args) 572 { 573 if (! PyArg_ParseTuple(args, ":GetVersion")) 574 return NULL; 575 576 return PyInt_FromLong((int) GetVersion()); 577 } 578 579 PyDoc_STRVAR(GetModuleFileName_doc, 580 "GetModuleFileName(module) -> path\n\ 581 \n\ 582 Return the fully-qualified path for the file that contains\n\ 583 the specified module. The module must have been loaded by the\n\ 584 current process.\n\ 585 \n\ 586 The module parameter should be a handle to the loaded module\n\ 587 whose path is being requested. If this parameter is 0, \n\ 588 GetModuleFileName retrieves the path of the executable file\n\ 589 of the current process."); 590 591 static PyObject * 592 sp_GetModuleFileName(PyObject* self, PyObject* args) 593 { 594 BOOL result; 595 HMODULE module; 596 TCHAR filename[MAX_PATH]; 597 598 if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM ":GetModuleFileName", 599 &module)) 600 return NULL; 601 602 result = GetModuleFileName(module, filename, MAX_PATH); 603 filename[MAX_PATH-1] = '\0'; 604 605 if (! result) 606 return PyErr_SetFromWindowsErr(GetLastError()); 607 608 return PyString_FromString(filename); 609 } 610 611 static PyMethodDef sp_functions[] = { 612 {"GetStdHandle", sp_GetStdHandle, METH_VARARGS, GetStdHandle_doc}, 613 {"GetCurrentProcess", sp_GetCurrentProcess, METH_VARARGS, 614 GetCurrentProcess_doc}, 615 {"DuplicateHandle", sp_DuplicateHandle, METH_VARARGS, 616 DuplicateHandle_doc}, 617 {"CreatePipe", sp_CreatePipe, METH_VARARGS, CreatePipe_doc}, 618 {"CreateProcess", sp_CreateProcess, METH_VARARGS, CreateProcess_doc}, 619 {"TerminateProcess", sp_TerminateProcess, METH_VARARGS, 620 TerminateProcess_doc}, 621 {"GetExitCodeProcess", sp_GetExitCodeProcess, METH_VARARGS, 622 GetExitCodeProcess_doc}, 623 {"WaitForSingleObject", sp_WaitForSingleObject, METH_VARARGS, 624 WaitForSingleObject_doc}, 625 {"GetVersion", sp_GetVersion, METH_VARARGS, GetVersion_doc}, 626 {"GetModuleFileName", sp_GetModuleFileName, METH_VARARGS, 627 GetModuleFileName_doc}, 628 {NULL, NULL} 629 }; 630 631 /* -------------------------------------------------------------------- */ 632 633 static void 634 defint(PyObject* d, const char* name, int value) 635 { 636 PyObject* v = PyInt_FromLong((long) value); 637 if (v) { 638 PyDict_SetItemString(d, (char*) name, v); 639 Py_DECREF(v); 640 } 641 } 642 643 #if PY_VERSION_HEX >= 0x02030000 644 PyMODINIT_FUNC 645 #else 646 DL_EXPORT(void) 647 #endif 648 init_subprocess() 649 { 650 PyObject *d; 651 PyObject *m; 652 653 /* patch up object descriptors */ 654 sp_handle_type.ob_type = &PyType_Type; 655 sp_handle_as_number.nb_int = (unaryfunc) sp_handle_as_int; 656 657 m = Py_InitModule("_subprocess", sp_functions); 658 if (m == NULL) 659 return; 660 d = PyModule_GetDict(m); 661 662 /* constants */ 663 defint(d, "STD_INPUT_HANDLE", STD_INPUT_HANDLE); 664 defint(d, "STD_OUTPUT_HANDLE", STD_OUTPUT_HANDLE); 665 defint(d, "STD_ERROR_HANDLE", STD_ERROR_HANDLE); 666 defint(d, "DUPLICATE_SAME_ACCESS", DUPLICATE_SAME_ACCESS); 667 defint(d, "STARTF_USESTDHANDLES", STARTF_USESTDHANDLES); 668 defint(d, "STARTF_USESHOWWINDOW", STARTF_USESHOWWINDOW); 669 defint(d, "SW_HIDE", SW_HIDE); 670 defint(d, "INFINITE", INFINITE); 671 defint(d, "WAIT_OBJECT_0", WAIT_OBJECT_0); 672 defint(d, "CREATE_NEW_CONSOLE", CREATE_NEW_CONSOLE); 673 defint(d, "CREATE_NEW_PROCESS_GROUP", CREATE_NEW_PROCESS_GROUP); 674 defint(d, "STILL_ACTIVE", STILL_ACTIVE); 675 } 676