D-Bus 1.6.12
|
00001 #include <config.h> 00002 00003 //#define SPAWN_DEBUG 00004 00005 #if !defined(SPAWN_DEBUG) || defined(_MSC_VER) 00006 #define PING() 00007 #else 00008 #define PING() fprintf (stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); fflush (stderr) 00009 #endif 00010 00011 #include <stdio.h> 00012 00013 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00014 /* dbus-spawn-win32.c Wrapper around g_spawn 00015 * 00016 * Copyright (C) 2002, 2003, 2004 Red Hat, Inc. 00017 * Copyright (C) 2003 CodeFactory AB 00018 * Copyright (C) 2005 Novell, Inc. 00019 * 00020 * Licensed under the Academic Free License version 2.1 00021 * 00022 * This program is free software; you can redistribute it and/or modify 00023 * it under the terms of the GNU General Public License as published by 00024 * the Free Software Foundation; either version 2 of the License, or 00025 * (at your option) any later version. 00026 * 00027 * This program is distributed in the hope that it will be useful, 00028 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00029 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00030 * GNU General Public License for more details. 00031 * 00032 * You should have received a copy of the GNU General Public License 00033 * along with this program; if not, write to the Free Software 00034 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00035 * 00036 */ 00037 #include "dbus-spawn.h" 00038 #include "dbus-sysdeps.h" 00039 #include "dbus-sysdeps-win.h" 00040 #include "dbus-internals.h" 00041 #include "dbus-test.h" 00042 #include "dbus-protocol.h" 00043 00044 #define WIN32_LEAN_AND_MEAN 00045 #include <windows.h> 00046 //#define STRICT 00047 //#include <windows.h> 00048 //#undef STRICT 00049 #include <winsock2.h> 00050 #undef interface 00051 00052 #include <stdlib.h> 00053 00054 #ifndef DBUS_WINCE 00055 #include <process.h> 00056 #endif 00057 00061 struct DBusBabysitter 00062 { 00063 int refcount; 00064 00065 HANDLE start_sync_event; 00066 #ifdef DBUS_BUILD_TESTS 00067 00068 HANDLE end_sync_event; 00069 #endif 00070 00071 char *executable; 00072 DBusSpawnChildSetupFunc child_setup; 00073 void *user_data; 00074 00075 int argc; 00076 char **argv; 00077 char **envp; 00078 00079 HANDLE child_handle; 00080 int socket_to_babysitter; /* Connection to the babysitter thread */ 00081 int socket_to_main; 00082 00083 DBusWatchList *watches; 00084 DBusWatch *sitter_watch; 00085 DBusBabysitterFinishedFunc finished_cb; 00086 void *finished_data; 00087 00088 dbus_bool_t have_spawn_errno; 00089 int spawn_errno; 00090 dbus_bool_t have_child_status; 00091 int child_status; 00092 }; 00093 00094 static DBusBabysitter* 00095 _dbus_babysitter_new (void) 00096 { 00097 DBusBabysitter *sitter; 00098 00099 sitter = dbus_new0 (DBusBabysitter, 1); 00100 if (sitter == NULL) 00101 return NULL; 00102 00103 sitter->refcount = 1; 00104 00105 sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL); 00106 if (sitter->start_sync_event == NULL) 00107 { 00108 _dbus_babysitter_unref (sitter); 00109 return NULL; 00110 } 00111 00112 #ifdef DBUS_BUILD_TESTS 00113 sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL); 00114 if (sitter->end_sync_event == NULL) 00115 { 00116 _dbus_babysitter_unref (sitter); 00117 return NULL; 00118 } 00119 #endif 00120 00121 sitter->child_handle = NULL; 00122 00123 sitter->socket_to_babysitter = sitter->socket_to_main = -1; 00124 00125 sitter->argc = 0; 00126 sitter->argv = NULL; 00127 sitter->envp = NULL; 00128 00129 sitter->watches = _dbus_watch_list_new (); 00130 if (sitter->watches == NULL) 00131 { 00132 _dbus_babysitter_unref (sitter); 00133 return NULL; 00134 } 00135 00136 sitter->have_spawn_errno = FALSE; 00137 sitter->have_child_status = FALSE; 00138 00139 return sitter; 00140 } 00141 00148 DBusBabysitter * 00149 _dbus_babysitter_ref (DBusBabysitter *sitter) 00150 { 00151 PING(); 00152 _dbus_assert (sitter != NULL); 00153 _dbus_assert (sitter->refcount > 0); 00154 00155 sitter->refcount += 1; 00156 00157 return sitter; 00158 } 00159 00160 static void 00161 close_socket_to_babysitter (DBusBabysitter *sitter) 00162 { 00163 _dbus_verbose ("Closing babysitter\n"); 00164 00165 if (sitter->sitter_watch != NULL) 00166 { 00167 _dbus_assert (sitter->watches != NULL); 00168 _dbus_watch_list_remove_watch (sitter->watches, sitter->sitter_watch); 00169 _dbus_watch_invalidate (sitter->sitter_watch); 00170 _dbus_watch_unref (sitter->sitter_watch); 00171 sitter->sitter_watch = NULL; 00172 } 00173 00174 if (sitter->socket_to_babysitter != -1) 00175 { 00176 _dbus_close_socket (sitter->socket_to_babysitter, NULL); 00177 sitter->socket_to_babysitter = -1; 00178 } 00179 } 00180 00186 void 00187 _dbus_babysitter_unref (DBusBabysitter *sitter) 00188 { 00189 int i; 00190 00191 PING(); 00192 _dbus_assert (sitter != NULL); 00193 _dbus_assert (sitter->refcount > 0); 00194 00195 sitter->refcount -= 1; 00196 00197 if (sitter->refcount == 0) 00198 { 00199 close_socket_to_babysitter (sitter); 00200 00201 if (sitter->socket_to_main != -1) 00202 { 00203 _dbus_close_socket (sitter->socket_to_main, NULL); 00204 sitter->socket_to_main = -1; 00205 } 00206 00207 PING(); 00208 if (sitter->argv != NULL) 00209 { 00210 for (i = 0; i < sitter->argc; i++) 00211 if (sitter->argv[i] != NULL) 00212 { 00213 dbus_free (sitter->argv[i]); 00214 sitter->argv[i] = NULL; 00215 } 00216 dbus_free (sitter->argv); 00217 sitter->argv = NULL; 00218 } 00219 00220 if (sitter->envp != NULL) 00221 { 00222 char **e = sitter->envp; 00223 00224 while (*e) 00225 dbus_free (*e++); 00226 dbus_free (sitter->envp); 00227 sitter->envp = NULL; 00228 } 00229 00230 if (sitter->child_handle != NULL) 00231 { 00232 CloseHandle (sitter->child_handle); 00233 sitter->child_handle = NULL; 00234 } 00235 00236 if (sitter->sitter_watch) 00237 { 00238 _dbus_watch_invalidate (sitter->sitter_watch); 00239 _dbus_watch_unref (sitter->sitter_watch); 00240 sitter->sitter_watch = NULL; 00241 } 00242 00243 if (sitter->watches) 00244 _dbus_watch_list_free (sitter->watches); 00245 00246 if (sitter->start_sync_event != NULL) 00247 { 00248 PING(); 00249 CloseHandle (sitter->start_sync_event); 00250 sitter->start_sync_event = NULL; 00251 } 00252 00253 #ifdef DBUS_BUILD_TESTS 00254 if (sitter->end_sync_event != NULL) 00255 { 00256 CloseHandle (sitter->end_sync_event); 00257 sitter->end_sync_event = NULL; 00258 } 00259 #endif 00260 00261 dbus_free (sitter->executable); 00262 00263 dbus_free (sitter); 00264 } 00265 } 00266 00267 void 00268 _dbus_babysitter_kill_child (DBusBabysitter *sitter) 00269 { 00270 PING(); 00271 if (sitter->child_handle == NULL) 00272 return; /* child is already dead, or we're so hosed we'll never recover */ 00273 00274 PING(); 00275 TerminateProcess (sitter->child_handle, 12345); 00276 } 00277 00283 dbus_bool_t 00284 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter) 00285 { 00286 PING(); 00287 return (sitter->child_handle == NULL); 00288 } 00289 00302 dbus_bool_t 00303 _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter, 00304 int *status) 00305 { 00306 if (!_dbus_babysitter_get_child_exited (sitter)) 00307 _dbus_assert_not_reached ("Child has not exited"); 00308 00309 if (!sitter->have_child_status || 00310 sitter->child_status == STILL_ACTIVE) 00311 return FALSE; 00312 00313 *status = sitter->child_status; 00314 return TRUE; 00315 } 00316 00326 void 00327 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter, 00328 DBusError *error) 00329 { 00330 PING(); 00331 if (!_dbus_babysitter_get_child_exited (sitter)) 00332 return; 00333 00334 PING(); 00335 if (sitter->have_spawn_errno) 00336 { 00337 char *emsg = _dbus_win_error_string (sitter->spawn_errno); 00338 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, 00339 "Failed to execute program %s: %s", 00340 sitter->executable, emsg); 00341 _dbus_win_free_error_string (emsg); 00342 } 00343 else if (sitter->have_child_status) 00344 { 00345 PING(); 00346 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED, 00347 "Process %s exited with status %d", 00348 sitter->executable, sitter->child_status); 00349 } 00350 else 00351 { 00352 PING(); 00353 dbus_set_error (error, DBUS_ERROR_FAILED, 00354 "Process %s exited, status unknown", 00355 sitter->executable); 00356 } 00357 PING(); 00358 } 00359 00360 dbus_bool_t 00361 _dbus_babysitter_set_watch_functions (DBusBabysitter *sitter, 00362 DBusAddWatchFunction add_function, 00363 DBusRemoveWatchFunction remove_function, 00364 DBusWatchToggledFunction toggled_function, 00365 void *data, 00366 DBusFreeFunction free_data_function) 00367 { 00368 PING(); 00369 return _dbus_watch_list_set_functions (sitter->watches, 00370 add_function, 00371 remove_function, 00372 toggled_function, 00373 data, 00374 free_data_function); 00375 } 00376 00377 static dbus_bool_t 00378 handle_watch (DBusWatch *watch, 00379 unsigned int condition, 00380 void *data) 00381 { 00382 DBusBabysitter *sitter = data; 00383 00384 /* On Unix dbus-spawn uses a babysitter *process*, thus it has to 00385 * actually send the exit statuses, error codes and whatnot through 00386 * sockets and/or pipes. On Win32, the babysitter is jus a thread, 00387 * so it can set the status fields directly in the babysitter struct 00388 * just fine. The socket pipe is used just so we can watch it with 00389 * select(), as soon as anything is written to it we know that the 00390 * babysitter thread has recorded the status in the babysitter 00391 * struct. 00392 */ 00393 00394 PING(); 00395 close_socket_to_babysitter (sitter); 00396 PING(); 00397 00398 if (_dbus_babysitter_get_child_exited (sitter) && 00399 sitter->finished_cb != NULL) 00400 { 00401 sitter->finished_cb (sitter, sitter->finished_data); 00402 sitter->finished_cb = NULL; 00403 } 00404 00405 return TRUE; 00406 } 00407 00408 /* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */ 00409 static int 00410 protect_argv (char **argv, 00411 char ***new_argv) 00412 { 00413 int i; 00414 int argc = 0; 00415 00416 while (argv[argc]) 00417 ++argc; 00418 *new_argv = dbus_malloc ((argc + 1) * sizeof (char *)); 00419 if (*new_argv == NULL) 00420 return -1; 00421 00422 for (i = 0; i < argc; i++) 00423 (*new_argv)[i] = NULL; 00424 00425 /* Quote each argv element if necessary, so that it will get 00426 * reconstructed correctly in the C runtime startup code. Note that 00427 * the unquoting algorithm in the C runtime is really weird, and 00428 * rather different than what Unix shells do. See stdargv.c in the C 00429 * runtime sources (in the Platform SDK, in src/crt). 00430 * 00431 * Note that an new_argv[0] constructed by this function should 00432 * *not* be passed as the filename argument to a spawn* or exec* 00433 * family function. That argument should be the real file name 00434 * without any quoting. 00435 */ 00436 for (i = 0; i < argc; i++) 00437 { 00438 char *p = argv[i]; 00439 char *q; 00440 int len = 0; 00441 int need_dblquotes = FALSE; 00442 while (*p) 00443 { 00444 if (*p == ' ' || *p == '\t') 00445 need_dblquotes = TRUE; 00446 else if (*p == '"') 00447 len++; 00448 else if (*p == '\\') 00449 { 00450 char *pp = p; 00451 while (*pp && *pp == '\\') 00452 pp++; 00453 if (*pp == '"') 00454 len++; 00455 } 00456 len++; 00457 p++; 00458 } 00459 00460 q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1); 00461 00462 if (q == NULL) 00463 return -1; 00464 00465 00466 p = argv[i]; 00467 00468 if (need_dblquotes) 00469 *q++ = '"'; 00470 00471 while (*p) 00472 { 00473 if (*p == '"') 00474 *q++ = '\\'; 00475 else if (*p == '\\') 00476 { 00477 char *pp = p; 00478 while (*pp && *pp == '\\') 00479 pp++; 00480 if (*pp == '"') 00481 *q++ = '\\'; 00482 } 00483 *q++ = *p; 00484 p++; 00485 } 00486 00487 if (need_dblquotes) 00488 *q++ = '"'; 00489 *q++ = '\0'; 00490 /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */ 00491 } 00492 (*new_argv)[argc] = NULL; 00493 00494 return argc; 00495 } 00496 00497 00498 /* From GPGME, relicensed by g10 Code GmbH. */ 00499 static char * 00500 compose_string (char **strings, char separator) 00501 { 00502 int i; 00503 int n = 0; 00504 char *buf; 00505 char *p; 00506 00507 if (!strings || !strings[0]) 00508 return 0; 00509 for (i = 0; strings[i]; i++) 00510 n += strlen (strings[i]) + 1; 00511 n++; 00512 00513 buf = p = malloc (n); 00514 if (!buf) 00515 return NULL; 00516 for (i = 0; strings[i]; i++) 00517 { 00518 strcpy (p, strings[i]); 00519 p += strlen (strings[i]); 00520 *(p++) = separator; 00521 } 00522 p--; 00523 *(p++) = '\0'; 00524 *p = '\0'; 00525 00526 return buf; 00527 } 00528 00529 static char * 00530 build_commandline (char **argv) 00531 { 00532 return compose_string (argv, ' '); 00533 } 00534 00535 static char * 00536 build_env_string (char** envp) 00537 { 00538 return compose_string (envp, '\0'); 00539 } 00540 00541 static HANDLE 00542 spawn_program (char* name, char** argv, char** envp) 00543 { 00544 PROCESS_INFORMATION pi = { NULL, 0, 0, 0 }; 00545 STARTUPINFOA si; 00546 char *arg_string, *env_string; 00547 BOOL result; 00548 00549 #ifdef DBUS_WINCE 00550 if (argv && argv[0]) 00551 arg_string = build_commandline (argv + 1); 00552 else 00553 arg_string = NULL; 00554 #else 00555 arg_string = build_commandline (argv); 00556 #endif 00557 if (!arg_string) 00558 return INVALID_HANDLE_VALUE; 00559 00560 env_string = build_env_string(envp); 00561 00562 memset (&si, 0, sizeof (si)); 00563 si.cb = sizeof (si); 00564 #ifdef DBUS_WINCE 00565 result = CreateProcessA (name, arg_string, NULL, NULL, FALSE, 0, 00566 #else 00567 result = CreateProcessA (NULL, arg_string, NULL, NULL, FALSE, 0, 00568 #endif 00569 (LPVOID)env_string, NULL, &si, &pi); 00570 free (arg_string); 00571 if (env_string) 00572 free (env_string); 00573 00574 if (!result) 00575 return INVALID_HANDLE_VALUE; 00576 00577 CloseHandle (pi.hThread); 00578 return pi.hProcess; 00579 } 00580 00581 00582 static DWORD __stdcall 00583 babysitter (void *parameter) 00584 { 00585 DBusBabysitter *sitter = (DBusBabysitter *) parameter; 00586 00587 PING(); 00588 _dbus_babysitter_ref (sitter); 00589 00590 if (sitter->child_setup) 00591 { 00592 PING(); 00593 (*sitter->child_setup) (sitter->user_data); 00594 } 00595 00596 _dbus_verbose ("babysitter: spawning %s\n", sitter->executable); 00597 00598 PING(); 00599 sitter->child_handle = spawn_program (sitter->executable, 00600 sitter->argv, sitter->envp); 00601 00602 PING(); 00603 if (sitter->child_handle == (HANDLE) -1) 00604 { 00605 sitter->child_handle = NULL; 00606 sitter->have_spawn_errno = TRUE; 00607 sitter->spawn_errno = GetLastError(); 00608 } 00609 00610 PING(); 00611 SetEvent (sitter->start_sync_event); 00612 00613 if (sitter->child_handle != NULL) 00614 { 00615 int ret; 00616 DWORD status; 00617 00618 PING(); 00619 WaitForSingleObject (sitter->child_handle, INFINITE); 00620 00621 PING(); 00622 ret = GetExitCodeProcess (sitter->child_handle, &status); 00623 00624 sitter->child_status = status; 00625 sitter->have_child_status = TRUE; 00626 00627 CloseHandle (sitter->child_handle); 00628 sitter->child_handle = NULL; 00629 } 00630 00631 #ifdef DBUS_BUILD_TESTS 00632 SetEvent (sitter->end_sync_event); 00633 #endif 00634 00635 PING(); 00636 send (sitter->socket_to_main, " ", 1, 0); 00637 00638 _dbus_babysitter_unref (sitter); 00639 00640 return 0; 00641 } 00642 00643 dbus_bool_t 00644 _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p, 00645 char **argv, 00646 char **envp, 00647 DBusSpawnChildSetupFunc child_setup, 00648 void *user_data, 00649 DBusError *error) 00650 { 00651 DBusBabysitter *sitter; 00652 HANDLE sitter_thread; 00653 DWORD sitter_thread_id; 00654 00655 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00656 00657 *sitter_p = NULL; 00658 00659 PING(); 00660 sitter = _dbus_babysitter_new (); 00661 if (sitter == NULL) 00662 { 00663 _DBUS_SET_OOM (error); 00664 return FALSE; 00665 } 00666 00667 sitter->child_setup = child_setup; 00668 sitter->user_data = user_data; 00669 00670 sitter->executable = _dbus_strdup (argv[0]); 00671 if (sitter->executable == NULL) 00672 { 00673 _DBUS_SET_OOM (error); 00674 goto out0; 00675 } 00676 00677 PING(); 00678 if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter, 00679 &sitter->socket_to_main, 00680 FALSE, error)) 00681 goto out0; 00682 00683 sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter, 00684 DBUS_WATCH_READABLE, 00685 TRUE, handle_watch, sitter, NULL); 00686 PING(); 00687 if (sitter->sitter_watch == NULL) 00688 { 00689 _DBUS_SET_OOM (error); 00690 goto out0; 00691 } 00692 00693 PING(); 00694 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch)) 00695 { 00696 /* we need to free it early so the destructor won't try to remove it 00697 * without it having been added, which DBusLoop doesn't allow */ 00698 _dbus_watch_invalidate (sitter->sitter_watch); 00699 _dbus_watch_unref (sitter->sitter_watch); 00700 sitter->sitter_watch = NULL; 00701 00702 _DBUS_SET_OOM (error); 00703 goto out0; 00704 } 00705 00706 sitter->argc = protect_argv (argv, &sitter->argv); 00707 if (sitter->argc == -1) 00708 { 00709 _DBUS_SET_OOM (error); 00710 goto out0; 00711 } 00712 sitter->envp = envp; 00713 00714 PING(); 00715 sitter_thread = (HANDLE) CreateThread (NULL, 0, babysitter, 00716 sitter, 0, &sitter_thread_id); 00717 00718 if (sitter_thread == 0) 00719 { 00720 PING(); 00721 dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED, 00722 "Failed to create new thread"); 00723 goto out0; 00724 } 00725 CloseHandle (sitter_thread); 00726 00727 PING(); 00728 WaitForSingleObject (sitter->start_sync_event, INFINITE); 00729 00730 PING(); 00731 if (sitter_p != NULL) 00732 *sitter_p = sitter; 00733 else 00734 _dbus_babysitter_unref (sitter); 00735 00736 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00737 00738 PING(); 00739 return TRUE; 00740 00741 out0: 00742 _dbus_babysitter_unref (sitter); 00743 00744 return FALSE; 00745 } 00746 00747 void 00748 _dbus_babysitter_set_result_function (DBusBabysitter *sitter, 00749 DBusBabysitterFinishedFunc finished, 00750 void *user_data) 00751 { 00752 sitter->finished_cb = finished; 00753 sitter->finished_data = user_data; 00754 } 00755 00756 #ifdef DBUS_BUILD_TESTS 00757 00758 static char * 00759 get_test_exec (const char *exe, 00760 DBusString *scratch_space) 00761 { 00762 const char *dbus_test_exec; 00763 00764 dbus_test_exec = _dbus_getenv ("DBUS_TEST_EXEC"); 00765 00766 if (dbus_test_exec == NULL) 00767 dbus_test_exec = DBUS_TEST_EXEC; 00768 00769 if (!_dbus_string_init (scratch_space)) 00770 return NULL; 00771 00772 if (!_dbus_string_append_printf (scratch_space, "%s/%s%s", 00773 dbus_test_exec, exe, DBUS_EXEEXT)) 00774 { 00775 _dbus_string_free (scratch_space); 00776 return NULL; 00777 } 00778 00779 return _dbus_string_get_data (scratch_space); 00780 } 00781 00782 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL) 00783 00784 static void 00785 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter) 00786 { 00787 if (sitter->child_handle == NULL) 00788 return; 00789 00790 WaitForSingleObject (sitter->end_sync_event, INFINITE); 00791 } 00792 00793 static dbus_bool_t 00794 check_spawn_nonexistent (void *data) 00795 { 00796 char *argv[4] = { NULL, NULL, NULL, NULL }; 00797 DBusBabysitter *sitter; 00798 DBusError error; 00799 00800 sitter = NULL; 00801 00802 dbus_error_init (&error); 00803 00804 /*** Test launching nonexistent binary */ 00805 00806 argv[0] = "/this/does/not/exist/32542sdgafgafdg"; 00807 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, 00808 NULL, NULL, 00809 &error)) 00810 { 00811 _dbus_babysitter_block_for_child_exit (sitter); 00812 _dbus_babysitter_set_child_exit_error (sitter, &error); 00813 } 00814 00815 if (sitter) 00816 _dbus_babysitter_unref (sitter); 00817 00818 if (!dbus_error_is_set (&error)) 00819 { 00820 _dbus_warn ("Did not get an error launching nonexistent executable\n"); 00821 return FALSE; 00822 } 00823 00824 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 00825 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED))) 00826 { 00827 _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n", 00828 error.name, error.message); 00829 dbus_error_free (&error); 00830 return FALSE; 00831 } 00832 00833 dbus_error_free (&error); 00834 00835 return TRUE; 00836 } 00837 00838 static dbus_bool_t 00839 check_spawn_segfault (void *data) 00840 { 00841 char *argv[4] = { NULL, NULL, NULL, NULL }; 00842 DBusBabysitter *sitter; 00843 DBusError error; 00844 DBusString argv0; 00845 00846 sitter = NULL; 00847 00848 dbus_error_init (&error); 00849 00850 /*** Test launching segfault binary */ 00851 00852 argv[0] = get_test_exec ("test-segfault", &argv0); 00853 00854 if (argv[0] == NULL) 00855 { 00856 /* OOM was simulated, never mind */ 00857 return TRUE; 00858 } 00859 00860 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, 00861 NULL, NULL, 00862 &error)) 00863 { 00864 _dbus_babysitter_block_for_child_exit (sitter); 00865 _dbus_babysitter_set_child_exit_error (sitter, &error); 00866 } 00867 00868 _dbus_string_free (&argv0); 00869 00870 if (sitter) 00871 _dbus_babysitter_unref (sitter); 00872 00873 if (!dbus_error_is_set (&error)) 00874 { 00875 _dbus_warn ("Did not get an error launching segfaulting binary\n"); 00876 return FALSE; 00877 } 00878 00879 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 00880 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) 00881 { 00882 _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n", 00883 error.name, error.message); 00884 dbus_error_free (&error); 00885 return FALSE; 00886 } 00887 00888 dbus_error_free (&error); 00889 00890 return TRUE; 00891 } 00892 00893 static dbus_bool_t 00894 check_spawn_exit (void *data) 00895 { 00896 char *argv[4] = { NULL, NULL, NULL, NULL }; 00897 DBusBabysitter *sitter; 00898 DBusError error; 00899 DBusString argv0; 00900 00901 sitter = NULL; 00902 00903 dbus_error_init (&error); 00904 00905 /*** Test launching exit failure binary */ 00906 00907 argv[0] = get_test_exec ("test-exit", &argv0); 00908 00909 if (argv[0] == NULL) 00910 { 00911 /* OOM was simulated, never mind */ 00912 return TRUE; 00913 } 00914 00915 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, 00916 NULL, NULL, 00917 &error)) 00918 { 00919 _dbus_babysitter_block_for_child_exit (sitter); 00920 _dbus_babysitter_set_child_exit_error (sitter, &error); 00921 } 00922 00923 _dbus_string_free (&argv0); 00924 00925 if (sitter) 00926 _dbus_babysitter_unref (sitter); 00927 00928 if (!dbus_error_is_set (&error)) 00929 { 00930 _dbus_warn ("Did not get an error launching binary that exited with failure code\n"); 00931 return FALSE; 00932 } 00933 00934 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 00935 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) 00936 { 00937 _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n", 00938 error.name, error.message); 00939 dbus_error_free (&error); 00940 return FALSE; 00941 } 00942 00943 dbus_error_free (&error); 00944 00945 return TRUE; 00946 } 00947 00948 static dbus_bool_t 00949 check_spawn_and_kill (void *data) 00950 { 00951 char *argv[4] = { NULL, NULL, NULL, NULL }; 00952 DBusBabysitter *sitter; 00953 DBusError error; 00954 DBusString argv0; 00955 00956 sitter = NULL; 00957 00958 dbus_error_init (&error); 00959 00960 /*** Test launching sleeping binary then killing it */ 00961 00962 argv[0] = get_test_exec ("test-sleep-forever", &argv0); 00963 00964 if (argv[0] == NULL) 00965 { 00966 /* OOM was simulated, never mind */ 00967 return TRUE; 00968 } 00969 00970 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, 00971 NULL, NULL, 00972 &error)) 00973 { 00974 _dbus_babysitter_kill_child (sitter); 00975 00976 _dbus_babysitter_block_for_child_exit (sitter); 00977 00978 _dbus_babysitter_set_child_exit_error (sitter, &error); 00979 } 00980 00981 _dbus_string_free (&argv0); 00982 00983 if (sitter) 00984 _dbus_babysitter_unref (sitter); 00985 00986 if (!dbus_error_is_set (&error)) 00987 { 00988 _dbus_warn ("Did not get an error after killing spawned binary\n"); 00989 return FALSE; 00990 } 00991 00992 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 00993 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) 00994 { 00995 _dbus_warn ("Not expecting error when killing executable: %s: %s\n", 00996 error.name, error.message); 00997 dbus_error_free (&error); 00998 return FALSE; 00999 } 01000 01001 dbus_error_free (&error); 01002 01003 return TRUE; 01004 } 01005 01006 dbus_bool_t 01007 _dbus_spawn_test (const char *test_data_dir) 01008 { 01009 if (!_dbus_test_oom_handling ("spawn_nonexistent", 01010 check_spawn_nonexistent, 01011 NULL)) 01012 return FALSE; 01013 01014 /* Don't run the obnoxious segfault test by default, 01015 * it's a pain to have to click all those error boxes. 01016 */ 01017 if (getenv ("DO_SEGFAULT_TEST")) 01018 if (!_dbus_test_oom_handling ("spawn_segfault", 01019 check_spawn_segfault, 01020 NULL)) 01021 return FALSE; 01022 01023 if (!_dbus_test_oom_handling ("spawn_exit", 01024 check_spawn_exit, 01025 NULL)) 01026 return FALSE; 01027 01028 if (!_dbus_test_oom_handling ("spawn_and_kill", 01029 check_spawn_and_kill, 01030 NULL)) 01031 return FALSE; 01032 01033 return TRUE; 01034 } 01035 #endif