D-Bus
1.4.16
|
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 //#define STRICT 00046 //#include <windows.h> 00047 //#undef STRICT 00048 #include <winsock2.h> 00049 #undef interface 00050 00051 #include <stdlib.h> 00052 00053 #ifndef DBUS_WINCE 00054 #include <process.h> 00055 #endif 00056 00060 struct DBusBabysitter 00061 { 00062 int refcount; 00063 00064 HANDLE start_sync_event; 00065 #ifdef DBUS_BUILD_TESTS 00066 00067 HANDLE end_sync_event; 00068 #endif 00069 00070 char *executable; 00071 DBusSpawnChildSetupFunc child_setup; 00072 void *user_data; 00073 00074 int argc; 00075 char **argv; 00076 char **envp; 00077 00078 HANDLE child_handle; 00079 int socket_to_babysitter; /* Connection to the babysitter thread */ 00080 int socket_to_main; 00081 00082 DBusWatchList *watches; 00083 DBusWatch *sitter_watch; 00084 00085 dbus_bool_t have_spawn_errno; 00086 int spawn_errno; 00087 dbus_bool_t have_child_status; 00088 int child_status; 00089 }; 00090 00091 static DBusBabysitter* 00092 _dbus_babysitter_new (void) 00093 { 00094 DBusBabysitter *sitter; 00095 00096 sitter = dbus_new0 (DBusBabysitter, 1); 00097 if (sitter == NULL) 00098 return NULL; 00099 00100 sitter->refcount = 1; 00101 00102 sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL); 00103 if (sitter->start_sync_event == NULL) 00104 { 00105 _dbus_babysitter_unref (sitter); 00106 return NULL; 00107 } 00108 00109 #ifdef DBUS_BUILD_TESTS 00110 sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL); 00111 if (sitter->end_sync_event == NULL) 00112 { 00113 _dbus_babysitter_unref (sitter); 00114 return NULL; 00115 } 00116 #endif 00117 00118 sitter->child_handle = NULL; 00119 00120 sitter->socket_to_babysitter = sitter->socket_to_main = -1; 00121 00122 sitter->argc = 0; 00123 sitter->argv = NULL; 00124 sitter->envp = NULL; 00125 00126 sitter->watches = _dbus_watch_list_new (); 00127 if (sitter->watches == NULL) 00128 { 00129 _dbus_babysitter_unref (sitter); 00130 return NULL; 00131 } 00132 00133 sitter->have_spawn_errno = FALSE; 00134 sitter->have_child_status = FALSE; 00135 00136 return sitter; 00137 } 00138 00145 DBusBabysitter * 00146 _dbus_babysitter_ref (DBusBabysitter *sitter) 00147 { 00148 PING(); 00149 _dbus_assert (sitter != NULL); 00150 _dbus_assert (sitter->refcount > 0); 00151 00152 sitter->refcount += 1; 00153 00154 return sitter; 00155 } 00156 00162 void 00163 _dbus_babysitter_unref (DBusBabysitter *sitter) 00164 { 00165 int i; 00166 00167 PING(); 00168 _dbus_assert (sitter != NULL); 00169 _dbus_assert (sitter->refcount > 0); 00170 00171 sitter->refcount -= 1; 00172 00173 if (sitter->refcount == 0) 00174 { 00175 if (sitter->socket_to_babysitter != -1) 00176 { 00177 _dbus_close_socket (sitter->socket_to_babysitter, NULL); 00178 sitter->socket_to_babysitter = -1; 00179 } 00180 00181 if (sitter->socket_to_main != -1) 00182 { 00183 _dbus_close_socket (sitter->socket_to_main, NULL); 00184 sitter->socket_to_main = -1; 00185 } 00186 00187 PING(); 00188 if (sitter->argv != NULL) 00189 { 00190 for (i = 0; i < sitter->argc; i++) 00191 if (sitter->argv[i] != NULL) 00192 { 00193 dbus_free (sitter->argv[i]); 00194 sitter->argv[i] = NULL; 00195 } 00196 dbus_free (sitter->argv); 00197 sitter->argv = NULL; 00198 } 00199 00200 if (sitter->envp != NULL) 00201 { 00202 char **e = sitter->envp; 00203 00204 while (*e) 00205 dbus_free (*e++); 00206 dbus_free (sitter->envp); 00207 sitter->envp = NULL; 00208 } 00209 00210 if (sitter->child_handle != NULL) 00211 { 00212 CloseHandle (sitter->child_handle); 00213 sitter->child_handle = NULL; 00214 } 00215 00216 if (sitter->sitter_watch) 00217 { 00218 _dbus_watch_invalidate (sitter->sitter_watch); 00219 _dbus_watch_unref (sitter->sitter_watch); 00220 sitter->sitter_watch = NULL; 00221 } 00222 00223 if (sitter->watches) 00224 _dbus_watch_list_free (sitter->watches); 00225 00226 if (sitter->start_sync_event != NULL) 00227 { 00228 PING(); 00229 CloseHandle (sitter->start_sync_event); 00230 sitter->start_sync_event = NULL; 00231 } 00232 00233 #ifdef DBUS_BUILD_TESTS 00234 if (sitter->end_sync_event != NULL) 00235 { 00236 CloseHandle (sitter->end_sync_event); 00237 sitter->end_sync_event = NULL; 00238 } 00239 #endif 00240 00241 dbus_free (sitter->executable); 00242 00243 dbus_free (sitter); 00244 } 00245 } 00246 00247 void 00248 _dbus_babysitter_kill_child (DBusBabysitter *sitter) 00249 { 00250 PING(); 00251 if (sitter->child_handle == NULL) 00252 return; /* child is already dead, or we're so hosed we'll never recover */ 00253 00254 PING(); 00255 TerminateProcess (sitter->child_handle, 12345); 00256 } 00257 00263 dbus_bool_t 00264 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter) 00265 { 00266 PING(); 00267 return (sitter->child_handle == NULL); 00268 } 00269 00282 dbus_bool_t 00283 _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter, 00284 int *status) 00285 { 00286 if (!_dbus_babysitter_get_child_exited (sitter)) 00287 _dbus_assert_not_reached ("Child has not exited"); 00288 00289 if (!sitter->have_child_status || 00290 sitter->child_status == STILL_ACTIVE) 00291 return FALSE; 00292 00293 *status = sitter->child_status; 00294 return TRUE; 00295 } 00296 00306 void 00307 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter, 00308 DBusError *error) 00309 { 00310 PING(); 00311 if (!_dbus_babysitter_get_child_exited (sitter)) 00312 return; 00313 00314 PING(); 00315 if (sitter->have_spawn_errno) 00316 { 00317 char *emsg = _dbus_win_error_string (sitter->spawn_errno); 00318 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, 00319 "Failed to execute program %s: %s", 00320 sitter->executable, emsg); 00321 _dbus_win_free_error_string (emsg); 00322 } 00323 else if (sitter->have_child_status) 00324 { 00325 PING(); 00326 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED, 00327 "Process %s exited with status %d", 00328 sitter->executable, sitter->child_status); 00329 } 00330 else 00331 { 00332 PING(); 00333 dbus_set_error (error, DBUS_ERROR_FAILED, 00334 "Process %s exited, status unknown", 00335 sitter->executable); 00336 } 00337 PING(); 00338 } 00339 00340 dbus_bool_t 00341 _dbus_babysitter_set_watch_functions (DBusBabysitter *sitter, 00342 DBusAddWatchFunction add_function, 00343 DBusRemoveWatchFunction remove_function, 00344 DBusWatchToggledFunction toggled_function, 00345 void *data, 00346 DBusFreeFunction free_data_function) 00347 { 00348 PING(); 00349 return _dbus_watch_list_set_functions (sitter->watches, 00350 add_function, 00351 remove_function, 00352 toggled_function, 00353 data, 00354 free_data_function); 00355 } 00356 00357 static dbus_bool_t 00358 handle_watch (DBusWatch *watch, 00359 unsigned int condition, 00360 void *data) 00361 { 00362 DBusBabysitter *sitter = data; 00363 00364 /* On Unix dbus-spawn uses a babysitter *process*, thus it has to 00365 * actually send the exit statuses, error codes and whatnot through 00366 * sockets and/or pipes. On Win32, the babysitter is jus a thread, 00367 * so it can set the status fields directly in the babysitter struct 00368 * just fine. The socket pipe is used just so we can watch it with 00369 * select(), as soon as anything is written to it we know that the 00370 * babysitter thread has recorded the status in the babysitter 00371 * struct. 00372 */ 00373 00374 PING(); 00375 _dbus_close_socket (sitter->socket_to_babysitter, NULL); 00376 PING(); 00377 sitter->socket_to_babysitter = -1; 00378 00379 return TRUE; 00380 } 00381 00382 /* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */ 00383 static int 00384 protect_argv (char **argv, 00385 char ***new_argv) 00386 { 00387 int i; 00388 int argc = 0; 00389 00390 while (argv[argc]) 00391 ++argc; 00392 *new_argv = dbus_malloc ((argc + 1) * sizeof (char *)); 00393 if (*new_argv == NULL) 00394 return -1; 00395 00396 for (i = 0; i < argc; i++) 00397 (*new_argv)[i] = NULL; 00398 00399 /* Quote each argv element if necessary, so that it will get 00400 * reconstructed correctly in the C runtime startup code. Note that 00401 * the unquoting algorithm in the C runtime is really weird, and 00402 * rather different than what Unix shells do. See stdargv.c in the C 00403 * runtime sources (in the Platform SDK, in src/crt). 00404 * 00405 * Note that an new_argv[0] constructed by this function should 00406 * *not* be passed as the filename argument to a spawn* or exec* 00407 * family function. That argument should be the real file name 00408 * without any quoting. 00409 */ 00410 for (i = 0; i < argc; i++) 00411 { 00412 char *p = argv[i]; 00413 char *q; 00414 int len = 0; 00415 int need_dblquotes = FALSE; 00416 while (*p) 00417 { 00418 if (*p == ' ' || *p == '\t') 00419 need_dblquotes = TRUE; 00420 else if (*p == '"') 00421 len++; 00422 else if (*p == '\\') 00423 { 00424 char *pp = p; 00425 while (*pp && *pp == '\\') 00426 pp++; 00427 if (*pp == '"') 00428 len++; 00429 } 00430 len++; 00431 p++; 00432 } 00433 00434 q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1); 00435 00436 if (q == NULL) 00437 return -1; 00438 00439 00440 p = argv[i]; 00441 00442 if (need_dblquotes) 00443 *q++ = '"'; 00444 00445 while (*p) 00446 { 00447 if (*p == '"') 00448 *q++ = '\\'; 00449 else if (*p == '\\') 00450 { 00451 char *pp = p; 00452 while (*pp && *pp == '\\') 00453 pp++; 00454 if (*pp == '"') 00455 *q++ = '\\'; 00456 } 00457 *q++ = *p; 00458 p++; 00459 } 00460 00461 if (need_dblquotes) 00462 *q++ = '"'; 00463 *q++ = '\0'; 00464 /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */ 00465 } 00466 (*new_argv)[argc] = NULL; 00467 00468 return argc; 00469 } 00470 00471 00472 /* From GPGME, relicensed by g10 Code GmbH. */ 00473 static char * 00474 compose_string (char **strings, char separator) 00475 { 00476 int i; 00477 int n = 0; 00478 char *buf; 00479 char *p; 00480 const char *ptr; 00481 00482 if (!strings || !strings[0]) 00483 return 0; 00484 for (i = 0; strings[i]; i++) 00485 n += strlen (strings[i]) + 1; 00486 n++; 00487 00488 buf = p = malloc (n); 00489 if (!buf) 00490 return NULL; 00491 for (i = 0; strings[i]; i++) 00492 { 00493 strcpy (p, strings[i]); 00494 p += strlen (strings[i]); 00495 *(p++) = separator; 00496 } 00497 p--; 00498 *(p++) = '\0'; 00499 *p = '\0'; 00500 00501 return buf; 00502 } 00503 00504 static char * 00505 build_commandline (char **argv) 00506 { 00507 return compose_string (argv, ' '); 00508 } 00509 00510 static char * 00511 build_env_string (char** envp) 00512 { 00513 return compose_string (envp, '\0'); 00514 } 00515 00516 static HANDLE 00517 spawn_program (char* name, char** argv, char** envp) 00518 { 00519 PROCESS_INFORMATION pi = { NULL, 0, 0, 0 }; 00520 STARTUPINFOA si; 00521 char *arg_string, *env_string; 00522 BOOL result; 00523 00524 #ifdef DBUS_WINCE 00525 if (argv && argv[0]) 00526 arg_string = build_commandline (argv + 1); 00527 else 00528 arg_string = NULL; 00529 #else 00530 arg_string = build_commandline (argv); 00531 #endif 00532 if (!arg_string) 00533 return INVALID_HANDLE_VALUE; 00534 00535 env_string = build_env_string(envp); 00536 00537 memset (&si, 0, sizeof (si)); 00538 si.cb = sizeof (si); 00539 #ifdef DBUS_WINCE 00540 result = CreateProcessA (name, arg_string, NULL, NULL, FALSE, 0, 00541 #else 00542 result = CreateProcessA (NULL, arg_string, NULL, NULL, FALSE, 0, 00543 #endif 00544 (LPVOID)env_string, NULL, &si, &pi); 00545 free (arg_string); 00546 if (env_string) 00547 free (env_string); 00548 00549 if (!result) 00550 return INVALID_HANDLE_VALUE; 00551 00552 CloseHandle (pi.hThread); 00553 return pi.hProcess; 00554 } 00555 00556 00557 static DWORD __stdcall 00558 babysitter (void *parameter) 00559 { 00560 DBusBabysitter *sitter = (DBusBabysitter *) parameter; 00561 int fd; 00562 PING(); 00563 _dbus_babysitter_ref (sitter); 00564 00565 if (sitter->child_setup) 00566 { 00567 PING(); 00568 (*sitter->child_setup) (sitter->user_data); 00569 } 00570 00571 _dbus_verbose ("babysitter: spawning %s\n", sitter->executable); 00572 00573 PING(); 00574 sitter->child_handle = spawn_program (sitter->executable, 00575 sitter->argv, sitter->envp); 00576 00577 PING(); 00578 if (sitter->child_handle == (HANDLE) -1) 00579 { 00580 sitter->child_handle = NULL; 00581 sitter->have_spawn_errno = TRUE; 00582 sitter->spawn_errno = GetLastError(); 00583 } 00584 00585 PING(); 00586 SetEvent (sitter->start_sync_event); 00587 00588 if (sitter->child_handle != NULL) 00589 { 00590 int ret; 00591 DWORD status; 00592 00593 PING(); 00594 WaitForSingleObject (sitter->child_handle, INFINITE); 00595 00596 PING(); 00597 ret = GetExitCodeProcess (sitter->child_handle, &status); 00598 00599 sitter->child_status = status; 00600 sitter->have_child_status = TRUE; 00601 00602 CloseHandle (sitter->child_handle); 00603 sitter->child_handle = NULL; 00604 } 00605 00606 #ifdef DBUS_BUILD_TESTS 00607 SetEvent (sitter->end_sync_event); 00608 #endif 00609 00610 PING(); 00611 send (sitter->socket_to_main, " ", 1, 0); 00612 00613 _dbus_babysitter_unref (sitter); 00614 00615 return 0; 00616 } 00617 00618 dbus_bool_t 00619 _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p, 00620 char **argv, 00621 char **envp, 00622 DBusSpawnChildSetupFunc child_setup, 00623 void *user_data, 00624 DBusError *error) 00625 { 00626 DBusBabysitter *sitter; 00627 HANDLE sitter_thread; 00628 DWORD sitter_thread_id; 00629 00630 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00631 00632 *sitter_p = NULL; 00633 00634 PING(); 00635 sitter = _dbus_babysitter_new (); 00636 if (sitter == NULL) 00637 { 00638 _DBUS_SET_OOM (error); 00639 return FALSE; 00640 } 00641 00642 sitter->child_setup = child_setup; 00643 sitter->user_data = user_data; 00644 00645 sitter->executable = _dbus_strdup (argv[0]); 00646 if (sitter->executable == NULL) 00647 { 00648 _DBUS_SET_OOM (error); 00649 goto out0; 00650 } 00651 00652 PING(); 00653 if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter, 00654 &sitter->socket_to_main, 00655 FALSE, error)) 00656 goto out0; 00657 00658 sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter, 00659 DBUS_WATCH_READABLE, 00660 TRUE, handle_watch, sitter, NULL); 00661 PING(); 00662 if (sitter->sitter_watch == NULL) 00663 { 00664 _DBUS_SET_OOM (error); 00665 goto out0; 00666 } 00667 00668 PING(); 00669 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch)) 00670 { 00671 _DBUS_SET_OOM (error); 00672 goto out0; 00673 } 00674 00675 sitter->argc = protect_argv (argv, &sitter->argv); 00676 if (sitter->argc == -1) 00677 { 00678 _DBUS_SET_OOM (error); 00679 goto out0; 00680 } 00681 sitter->envp = envp; 00682 00683 PING(); 00684 sitter_thread = (HANDLE) CreateThread (NULL, 0, babysitter, 00685 sitter, 0, &sitter_thread_id); 00686 00687 if (sitter_thread == 0) 00688 { 00689 PING(); 00690 dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED, 00691 "Failed to create new thread"); 00692 goto out0; 00693 } 00694 CloseHandle (sitter_thread); 00695 00696 PING(); 00697 WaitForSingleObject (sitter->start_sync_event, INFINITE); 00698 00699 PING(); 00700 if (sitter_p != NULL) 00701 *sitter_p = sitter; 00702 else 00703 _dbus_babysitter_unref (sitter); 00704 00705 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00706 00707 PING(); 00708 return TRUE; 00709 00710 out0: 00711 _dbus_babysitter_unref (sitter); 00712 00713 return FALSE; 00714 } 00715 00716 #ifdef DBUS_BUILD_TESTS 00717 00718 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL) 00719 00720 static void 00721 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter) 00722 { 00723 if (sitter->child_handle == NULL) 00724 return; 00725 00726 WaitForSingleObject (sitter->end_sync_event, INFINITE); 00727 } 00728 00729 static dbus_bool_t 00730 check_spawn_nonexistent (void *data) 00731 { 00732 char *argv[4] = { NULL, NULL, NULL, NULL }; 00733 DBusBabysitter *sitter; 00734 DBusError error; 00735 00736 sitter = NULL; 00737 00738 dbus_error_init (&error); 00739 00740 /*** Test launching nonexistent binary */ 00741 00742 argv[0] = "/this/does/not/exist/32542sdgafgafdg"; 00743 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, 00744 NULL, NULL, 00745 &error)) 00746 { 00747 _dbus_babysitter_block_for_child_exit (sitter); 00748 _dbus_babysitter_set_child_exit_error (sitter, &error); 00749 } 00750 00751 if (sitter) 00752 _dbus_babysitter_unref (sitter); 00753 00754 if (!dbus_error_is_set (&error)) 00755 { 00756 _dbus_warn ("Did not get an error launching nonexistent executable\n"); 00757 return FALSE; 00758 } 00759 00760 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 00761 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED))) 00762 { 00763 _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n", 00764 error.name, error.message); 00765 dbus_error_free (&error); 00766 return FALSE; 00767 } 00768 00769 dbus_error_free (&error); 00770 00771 return TRUE; 00772 } 00773 00774 static dbus_bool_t 00775 check_spawn_segfault (void *data) 00776 { 00777 char *argv[4] = { NULL, NULL, NULL, NULL }; 00778 DBusBabysitter *sitter; 00779 DBusError error; 00780 00781 sitter = NULL; 00782 00783 dbus_error_init (&error); 00784 00785 /*** Test launching segfault binary */ 00786 00787 argv[0] = TEST_SEGFAULT_BINARY; 00788 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, 00789 NULL, NULL, 00790 &error)) 00791 { 00792 _dbus_babysitter_block_for_child_exit (sitter); 00793 _dbus_babysitter_set_child_exit_error (sitter, &error); 00794 } 00795 00796 if (sitter) 00797 _dbus_babysitter_unref (sitter); 00798 00799 if (!dbus_error_is_set (&error)) 00800 { 00801 _dbus_warn ("Did not get an error launching segfaulting binary\n"); 00802 return FALSE; 00803 } 00804 00805 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 00806 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) 00807 { 00808 _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n", 00809 error.name, error.message); 00810 dbus_error_free (&error); 00811 return FALSE; 00812 } 00813 00814 dbus_error_free (&error); 00815 00816 return TRUE; 00817 } 00818 00819 static dbus_bool_t 00820 check_spawn_exit (void *data) 00821 { 00822 char *argv[4] = { NULL, NULL, NULL, NULL }; 00823 DBusBabysitter *sitter; 00824 DBusError error; 00825 00826 sitter = NULL; 00827 00828 dbus_error_init (&error); 00829 00830 /*** Test launching exit failure binary */ 00831 00832 argv[0] = TEST_EXIT_BINARY; 00833 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, 00834 NULL, NULL, 00835 &error)) 00836 { 00837 _dbus_babysitter_block_for_child_exit (sitter); 00838 _dbus_babysitter_set_child_exit_error (sitter, &error); 00839 } 00840 00841 if (sitter) 00842 _dbus_babysitter_unref (sitter); 00843 00844 if (!dbus_error_is_set (&error)) 00845 { 00846 _dbus_warn ("Did not get an error launching binary that exited with failure code\n"); 00847 return FALSE; 00848 } 00849 00850 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 00851 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) 00852 { 00853 _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n", 00854 error.name, error.message); 00855 dbus_error_free (&error); 00856 return FALSE; 00857 } 00858 00859 dbus_error_free (&error); 00860 00861 return TRUE; 00862 } 00863 00864 static dbus_bool_t 00865 check_spawn_and_kill (void *data) 00866 { 00867 char *argv[4] = { NULL, NULL, NULL, NULL }; 00868 DBusBabysitter *sitter; 00869 DBusError error; 00870 00871 sitter = NULL; 00872 00873 dbus_error_init (&error); 00874 00875 /*** Test launching sleeping binary then killing it */ 00876 00877 argv[0] = TEST_SLEEP_FOREVER_BINARY; 00878 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, 00879 NULL, NULL, 00880 &error)) 00881 { 00882 _dbus_babysitter_kill_child (sitter); 00883 00884 _dbus_babysitter_block_for_child_exit (sitter); 00885 00886 _dbus_babysitter_set_child_exit_error (sitter, &error); 00887 } 00888 00889 if (sitter) 00890 _dbus_babysitter_unref (sitter); 00891 00892 if (!dbus_error_is_set (&error)) 00893 { 00894 _dbus_warn ("Did not get an error after killing spawned binary\n"); 00895 return FALSE; 00896 } 00897 00898 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 00899 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) 00900 { 00901 _dbus_warn ("Not expecting error when killing executable: %s: %s\n", 00902 error.name, error.message); 00903 dbus_error_free (&error); 00904 return FALSE; 00905 } 00906 00907 dbus_error_free (&error); 00908 00909 return TRUE; 00910 } 00911 00912 dbus_bool_t 00913 _dbus_spawn_test (const char *test_data_dir) 00914 { 00915 if (!_dbus_test_oom_handling ("spawn_nonexistent", 00916 check_spawn_nonexistent, 00917 NULL)) 00918 return FALSE; 00919 00920 /* Don't run the obnoxious segfault test by default, 00921 * it's a pain to have to click all those error boxes. 00922 */ 00923 if (getenv ("DO_SEGFAULT_TEST")) 00924 if (!_dbus_test_oom_handling ("spawn_segfault", 00925 check_spawn_segfault, 00926 NULL)) 00927 return FALSE; 00928 00929 if (!_dbus_test_oom_handling ("spawn_exit", 00930 check_spawn_exit, 00931 NULL)) 00932 return FALSE; 00933 00934 if (!_dbus_test_oom_handling ("spawn_and_kill", 00935 check_spawn_and_kill, 00936 NULL)) 00937 return FALSE; 00938 00939 return TRUE; 00940 } 00941 #endif