00001 #include <config.h>
00002
00003
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
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
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
00046
00047
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;
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;
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
00365
00366
00367
00368
00369
00370
00371
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
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
00400
00401
00402
00403
00404
00405
00406
00407
00408
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
00465 }
00466 (*new_argv)[argc] = NULL;
00467
00468 return argc;
00469 }
00470
00471
00472
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
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
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
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
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
00921
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