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 #include <windows.h>
00046
00047
00048
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;
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;
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
00385
00386
00387
00388
00389
00390
00391
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
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
00426
00427
00428
00429
00430
00431
00432
00433
00434
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
00491 }
00492 (*new_argv)[argc] = NULL;
00493
00494 return argc;
00495 }
00496
00497
00498
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
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 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
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
00851
00852 argv[0] = get_test_exec ("test-segfault", &argv0);
00853
00854 if (argv[0] == NULL)
00855 {
00856
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
00906
00907 argv[0] = get_test_exec ("test-exit", &argv0);
00908
00909 if (argv[0] == NULL)
00910 {
00911
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
00961
00962 argv[0] = get_test_exec ("test-sleep-forever", &argv0);
00963
00964 if (argv[0] == NULL)
00965 {
00966
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
01015
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