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 DBusBabysitterFinishedFunc finished_cb;
00085 void *finished_data;
00086
00087 dbus_bool_t have_spawn_errno;
00088 int spawn_errno;
00089 dbus_bool_t have_child_status;
00090 int child_status;
00091 };
00092
00093 static DBusBabysitter*
00094 _dbus_babysitter_new (void)
00095 {
00096 DBusBabysitter *sitter;
00097
00098 sitter = dbus_new0 (DBusBabysitter, 1);
00099 if (sitter == NULL)
00100 return NULL;
00101
00102 sitter->refcount = 1;
00103
00104 sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
00105 if (sitter->start_sync_event == NULL)
00106 {
00107 _dbus_babysitter_unref (sitter);
00108 return NULL;
00109 }
00110
00111 #ifdef DBUS_BUILD_TESTS
00112 sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
00113 if (sitter->end_sync_event == NULL)
00114 {
00115 _dbus_babysitter_unref (sitter);
00116 return NULL;
00117 }
00118 #endif
00119
00120 sitter->child_handle = NULL;
00121
00122 sitter->socket_to_babysitter = sitter->socket_to_main = -1;
00123
00124 sitter->argc = 0;
00125 sitter->argv = NULL;
00126 sitter->envp = NULL;
00127
00128 sitter->watches = _dbus_watch_list_new ();
00129 if (sitter->watches == NULL)
00130 {
00131 _dbus_babysitter_unref (sitter);
00132 return NULL;
00133 }
00134
00135 sitter->have_spawn_errno = FALSE;
00136 sitter->have_child_status = FALSE;
00137
00138 return sitter;
00139 }
00140
00147 DBusBabysitter *
00148 _dbus_babysitter_ref (DBusBabysitter *sitter)
00149 {
00150 PING();
00151 _dbus_assert (sitter != NULL);
00152 _dbus_assert (sitter->refcount > 0);
00153
00154 sitter->refcount += 1;
00155
00156 return sitter;
00157 }
00158
00159 static void
00160 close_socket_to_babysitter (DBusBabysitter *sitter)
00161 {
00162 _dbus_verbose ("Closing babysitter\n");
00163
00164 if (sitter->sitter_watch != NULL)
00165 {
00166 _dbus_assert (sitter->watches != NULL);
00167 _dbus_watch_list_remove_watch (sitter->watches, sitter->sitter_watch);
00168 _dbus_watch_invalidate (sitter->sitter_watch);
00169 _dbus_watch_unref (sitter->sitter_watch);
00170 sitter->sitter_watch = NULL;
00171 }
00172
00173 if (sitter->socket_to_babysitter != -1)
00174 {
00175 _dbus_close_socket (sitter->socket_to_babysitter, NULL);
00176 sitter->socket_to_babysitter = -1;
00177 }
00178 }
00179
00185 void
00186 _dbus_babysitter_unref (DBusBabysitter *sitter)
00187 {
00188 int i;
00189
00190 PING();
00191 _dbus_assert (sitter != NULL);
00192 _dbus_assert (sitter->refcount > 0);
00193
00194 sitter->refcount -= 1;
00195
00196 if (sitter->refcount == 0)
00197 {
00198 close_socket_to_babysitter (sitter);
00199
00200 if (sitter->socket_to_main != -1)
00201 {
00202 _dbus_close_socket (sitter->socket_to_main, NULL);
00203 sitter->socket_to_main = -1;
00204 }
00205
00206 PING();
00207 if (sitter->argv != NULL)
00208 {
00209 for (i = 0; i < sitter->argc; i++)
00210 if (sitter->argv[i] != NULL)
00211 {
00212 dbus_free (sitter->argv[i]);
00213 sitter->argv[i] = NULL;
00214 }
00215 dbus_free (sitter->argv);
00216 sitter->argv = NULL;
00217 }
00218
00219 if (sitter->envp != NULL)
00220 {
00221 char **e = sitter->envp;
00222
00223 while (*e)
00224 dbus_free (*e++);
00225 dbus_free (sitter->envp);
00226 sitter->envp = NULL;
00227 }
00228
00229 if (sitter->child_handle != NULL)
00230 {
00231 CloseHandle (sitter->child_handle);
00232 sitter->child_handle = NULL;
00233 }
00234
00235 if (sitter->sitter_watch)
00236 {
00237 _dbus_watch_invalidate (sitter->sitter_watch);
00238 _dbus_watch_unref (sitter->sitter_watch);
00239 sitter->sitter_watch = NULL;
00240 }
00241
00242 if (sitter->watches)
00243 _dbus_watch_list_free (sitter->watches);
00244
00245 if (sitter->start_sync_event != NULL)
00246 {
00247 PING();
00248 CloseHandle (sitter->start_sync_event);
00249 sitter->start_sync_event = NULL;
00250 }
00251
00252 #ifdef DBUS_BUILD_TESTS
00253 if (sitter->end_sync_event != NULL)
00254 {
00255 CloseHandle (sitter->end_sync_event);
00256 sitter->end_sync_event = NULL;
00257 }
00258 #endif
00259
00260 dbus_free (sitter->executable);
00261
00262 dbus_free (sitter);
00263 }
00264 }
00265
00266 void
00267 _dbus_babysitter_kill_child (DBusBabysitter *sitter)
00268 {
00269 PING();
00270 if (sitter->child_handle == NULL)
00271 return;
00272
00273 PING();
00274 TerminateProcess (sitter->child_handle, 12345);
00275 }
00276
00282 dbus_bool_t
00283 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
00284 {
00285 PING();
00286 return (sitter->child_handle == NULL);
00287 }
00288
00301 dbus_bool_t
00302 _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter,
00303 int *status)
00304 {
00305 if (!_dbus_babysitter_get_child_exited (sitter))
00306 _dbus_assert_not_reached ("Child has not exited");
00307
00308 if (!sitter->have_child_status ||
00309 sitter->child_status == STILL_ACTIVE)
00310 return FALSE;
00311
00312 *status = sitter->child_status;
00313 return TRUE;
00314 }
00315
00325 void
00326 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
00327 DBusError *error)
00328 {
00329 PING();
00330 if (!_dbus_babysitter_get_child_exited (sitter))
00331 return;
00332
00333 PING();
00334 if (sitter->have_spawn_errno)
00335 {
00336 char *emsg = _dbus_win_error_string (sitter->spawn_errno);
00337 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
00338 "Failed to execute program %s: %s",
00339 sitter->executable, emsg);
00340 _dbus_win_free_error_string (emsg);
00341 }
00342 else if (sitter->have_child_status)
00343 {
00344 PING();
00345 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
00346 "Process %s exited with status %d",
00347 sitter->executable, sitter->child_status);
00348 }
00349 else
00350 {
00351 PING();
00352 dbus_set_error (error, DBUS_ERROR_FAILED,
00353 "Process %s exited, status unknown",
00354 sitter->executable);
00355 }
00356 PING();
00357 }
00358
00359 dbus_bool_t
00360 _dbus_babysitter_set_watch_functions (DBusBabysitter *sitter,
00361 DBusAddWatchFunction add_function,
00362 DBusRemoveWatchFunction remove_function,
00363 DBusWatchToggledFunction toggled_function,
00364 void *data,
00365 DBusFreeFunction free_data_function)
00366 {
00367 PING();
00368 return _dbus_watch_list_set_functions (sitter->watches,
00369 add_function,
00370 remove_function,
00371 toggled_function,
00372 data,
00373 free_data_function);
00374 }
00375
00376 static dbus_bool_t
00377 handle_watch (DBusWatch *watch,
00378 unsigned int condition,
00379 void *data)
00380 {
00381 DBusBabysitter *sitter = data;
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393 PING();
00394 close_socket_to_babysitter (sitter);
00395 PING();
00396
00397 if (_dbus_babysitter_get_child_exited (sitter) &&
00398 sitter->finished_cb != NULL)
00399 {
00400 sitter->finished_cb (sitter, sitter->finished_data);
00401 sitter->finished_cb = NULL;
00402 }
00403
00404 return TRUE;
00405 }
00406
00407
00408 static int
00409 protect_argv (char **argv,
00410 char ***new_argv)
00411 {
00412 int i;
00413 int argc = 0;
00414
00415 while (argv[argc])
00416 ++argc;
00417 *new_argv = dbus_malloc ((argc + 1) * sizeof (char *));
00418 if (*new_argv == NULL)
00419 return -1;
00420
00421 for (i = 0; i < argc; i++)
00422 (*new_argv)[i] = NULL;
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435 for (i = 0; i < argc; i++)
00436 {
00437 char *p = argv[i];
00438 char *q;
00439 int len = 0;
00440 int need_dblquotes = FALSE;
00441 while (*p)
00442 {
00443 if (*p == ' ' || *p == '\t')
00444 need_dblquotes = TRUE;
00445 else if (*p == '"')
00446 len++;
00447 else if (*p == '\\')
00448 {
00449 char *pp = p;
00450 while (*pp && *pp == '\\')
00451 pp++;
00452 if (*pp == '"')
00453 len++;
00454 }
00455 len++;
00456 p++;
00457 }
00458
00459 q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1);
00460
00461 if (q == NULL)
00462 return -1;
00463
00464
00465 p = argv[i];
00466
00467 if (need_dblquotes)
00468 *q++ = '"';
00469
00470 while (*p)
00471 {
00472 if (*p == '"')
00473 *q++ = '\\';
00474 else if (*p == '\\')
00475 {
00476 char *pp = p;
00477 while (*pp && *pp == '\\')
00478 pp++;
00479 if (*pp == '"')
00480 *q++ = '\\';
00481 }
00482 *q++ = *p;
00483 p++;
00484 }
00485
00486 if (need_dblquotes)
00487 *q++ = '"';
00488 *q++ = '\0';
00489
00490 }
00491 (*new_argv)[argc] = NULL;
00492
00493 return argc;
00494 }
00495
00496
00497
00498 static char *
00499 compose_string (char **strings, char separator)
00500 {
00501 int i;
00502 int n = 0;
00503 char *buf;
00504 char *p;
00505 const char *ptr;
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 int fd;
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
00697
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 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)
00759
00760 static void
00761 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
00762 {
00763 if (sitter->child_handle == NULL)
00764 return;
00765
00766 WaitForSingleObject (sitter->end_sync_event, INFINITE);
00767 }
00768
00769 static dbus_bool_t
00770 check_spawn_nonexistent (void *data)
00771 {
00772 char *argv[4] = { NULL, NULL, NULL, NULL };
00773 DBusBabysitter *sitter;
00774 DBusError error;
00775
00776 sitter = NULL;
00777
00778 dbus_error_init (&error);
00779
00780
00781
00782 argv[0] = "/this/does/not/exist/32542sdgafgafdg";
00783 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00784 NULL, NULL,
00785 &error))
00786 {
00787 _dbus_babysitter_block_for_child_exit (sitter);
00788 _dbus_babysitter_set_child_exit_error (sitter, &error);
00789 }
00790
00791 if (sitter)
00792 _dbus_babysitter_unref (sitter);
00793
00794 if (!dbus_error_is_set (&error))
00795 {
00796 _dbus_warn ("Did not get an error launching nonexistent executable\n");
00797 return FALSE;
00798 }
00799
00800 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00801 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
00802 {
00803 _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
00804 error.name, error.message);
00805 dbus_error_free (&error);
00806 return FALSE;
00807 }
00808
00809 dbus_error_free (&error);
00810
00811 return TRUE;
00812 }
00813
00814 static dbus_bool_t
00815 check_spawn_segfault (void *data)
00816 {
00817 char *argv[4] = { NULL, NULL, NULL, NULL };
00818 DBusBabysitter *sitter;
00819 DBusError error;
00820
00821 sitter = NULL;
00822
00823 dbus_error_init (&error);
00824
00825
00826
00827 argv[0] = TEST_SEGFAULT_BINARY;
00828 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00829 NULL, NULL,
00830 &error))
00831 {
00832 _dbus_babysitter_block_for_child_exit (sitter);
00833 _dbus_babysitter_set_child_exit_error (sitter, &error);
00834 }
00835
00836 if (sitter)
00837 _dbus_babysitter_unref (sitter);
00838
00839 if (!dbus_error_is_set (&error))
00840 {
00841 _dbus_warn ("Did not get an error launching segfaulting binary\n");
00842 return FALSE;
00843 }
00844
00845 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00846 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
00847 {
00848 _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
00849 error.name, error.message);
00850 dbus_error_free (&error);
00851 return FALSE;
00852 }
00853
00854 dbus_error_free (&error);
00855
00856 return TRUE;
00857 }
00858
00859 static dbus_bool_t
00860 check_spawn_exit (void *data)
00861 {
00862 char *argv[4] = { NULL, NULL, NULL, NULL };
00863 DBusBabysitter *sitter;
00864 DBusError error;
00865
00866 sitter = NULL;
00867
00868 dbus_error_init (&error);
00869
00870
00871
00872 argv[0] = TEST_EXIT_BINARY;
00873 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00874 NULL, NULL,
00875 &error))
00876 {
00877 _dbus_babysitter_block_for_child_exit (sitter);
00878 _dbus_babysitter_set_child_exit_error (sitter, &error);
00879 }
00880
00881 if (sitter)
00882 _dbus_babysitter_unref (sitter);
00883
00884 if (!dbus_error_is_set (&error))
00885 {
00886 _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
00887 return FALSE;
00888 }
00889
00890 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00891 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
00892 {
00893 _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
00894 error.name, error.message);
00895 dbus_error_free (&error);
00896 return FALSE;
00897 }
00898
00899 dbus_error_free (&error);
00900
00901 return TRUE;
00902 }
00903
00904 static dbus_bool_t
00905 check_spawn_and_kill (void *data)
00906 {
00907 char *argv[4] = { NULL, NULL, NULL, NULL };
00908 DBusBabysitter *sitter;
00909 DBusError error;
00910
00911 sitter = NULL;
00912
00913 dbus_error_init (&error);
00914
00915
00916
00917 argv[0] = TEST_SLEEP_FOREVER_BINARY;
00918 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00919 NULL, NULL,
00920 &error))
00921 {
00922 _dbus_babysitter_kill_child (sitter);
00923
00924 _dbus_babysitter_block_for_child_exit (sitter);
00925
00926 _dbus_babysitter_set_child_exit_error (sitter, &error);
00927 }
00928
00929 if (sitter)
00930 _dbus_babysitter_unref (sitter);
00931
00932 if (!dbus_error_is_set (&error))
00933 {
00934 _dbus_warn ("Did not get an error after killing spawned binary\n");
00935 return FALSE;
00936 }
00937
00938 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00939 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
00940 {
00941 _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
00942 error.name, error.message);
00943 dbus_error_free (&error);
00944 return FALSE;
00945 }
00946
00947 dbus_error_free (&error);
00948
00949 return TRUE;
00950 }
00951
00952 dbus_bool_t
00953 _dbus_spawn_test (const char *test_data_dir)
00954 {
00955 if (!_dbus_test_oom_handling ("spawn_nonexistent",
00956 check_spawn_nonexistent,
00957 NULL))
00958 return FALSE;
00959
00960
00961
00962
00963 if (getenv ("DO_SEGFAULT_TEST"))
00964 if (!_dbus_test_oom_handling ("spawn_segfault",
00965 check_spawn_segfault,
00966 NULL))
00967 return FALSE;
00968
00969 if (!_dbus_test_oom_handling ("spawn_exit",
00970 check_spawn_exit,
00971 NULL))
00972 return FALSE;
00973
00974 if (!_dbus_test_oom_handling ("spawn_and_kill",
00975 check_spawn_and_kill,
00976 NULL))
00977 return FALSE;
00978
00979 return TRUE;
00980 }
00981 #endif