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 DBusAtomic refcount;
00064
00065 HANDLE start_sync_event;
00066 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00067
00068 HANDLE end_sync_event;
00069 #endif
00070
00071 char *log_name;
00072 DBusSpawnChildSetupFunc child_setup;
00073 void *user_data;
00074
00075 int argc;
00076 char **argv;
00077 char **envp;
00078
00079 HANDLE child_handle;
00080 DBusSocket socket_to_babysitter;
00081 DBusSocket 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 void
00095 _dbus_babysitter_trace_ref (DBusBabysitter *sitter,
00096 int old_refcount,
00097 int new_refcount,
00098 const char *why)
00099 {
00100 #ifdef DBUS_ENABLE_VERBOSE_MODE
00101 static int enabled = -1;
00102
00103 _dbus_trace_ref ("DBusBabysitter", sitter, old_refcount, new_refcount, why,
00104 "DBUS_BABYSITTER_TRACE", &enabled);
00105 #endif
00106 }
00107
00108 static DBusBabysitter*
00109 _dbus_babysitter_new (void)
00110 {
00111 DBusBabysitter *sitter;
00112 dbus_int32_t old_refcount;
00113
00114 sitter = dbus_new0 (DBusBabysitter, 1);
00115 if (sitter == NULL)
00116 return NULL;
00117
00118 old_refcount = _dbus_atomic_inc (&sitter->refcount);
00119
00120 _dbus_babysitter_trace_ref (sitter, old_refcount, old_refcount+1, __FUNCTION__);
00121
00122 sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
00123 if (sitter->start_sync_event == NULL)
00124 {
00125 _dbus_babysitter_unref (sitter);
00126 return NULL;
00127 }
00128
00129 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00130 sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
00131 if (sitter->end_sync_event == NULL)
00132 {
00133 _dbus_babysitter_unref (sitter);
00134 return NULL;
00135 }
00136 #endif
00137
00138 sitter->child_handle = NULL;
00139
00140 sitter->socket_to_babysitter = sitter->socket_to_main = _dbus_socket_get_invalid ();
00141
00142 sitter->argc = 0;
00143 sitter->argv = NULL;
00144 sitter->envp = NULL;
00145
00146 sitter->watches = _dbus_watch_list_new ();
00147 if (sitter->watches == NULL)
00148 {
00149 _dbus_babysitter_unref (sitter);
00150 return NULL;
00151 }
00152
00153 sitter->have_spawn_errno = FALSE;
00154 sitter->have_child_status = FALSE;
00155
00156 return sitter;
00157 }
00158
00165 DBusBabysitter *
00166 _dbus_babysitter_ref (DBusBabysitter *sitter)
00167 {
00168 dbus_int32_t old_refcount;
00169 PING();
00170 _dbus_assert (sitter != NULL);
00171
00172 old_refcount = _dbus_atomic_inc (&sitter->refcount);
00173 _dbus_assert (old_refcount > 0);
00174 _dbus_babysitter_trace_ref (sitter, old_refcount, old_refcount+1, __FUNCTION__);
00175
00176 return sitter;
00177 }
00178
00179 static void
00180 close_socket_to_babysitter (DBusBabysitter *sitter)
00181 {
00182 _dbus_verbose ("Closing babysitter\n");
00183
00184 if (sitter->sitter_watch != NULL)
00185 {
00186 _dbus_assert (sitter->watches != NULL);
00187 _dbus_watch_list_remove_watch (sitter->watches, sitter->sitter_watch);
00188 _dbus_watch_invalidate (sitter->sitter_watch);
00189 _dbus_watch_unref (sitter->sitter_watch);
00190 sitter->sitter_watch = NULL;
00191 }
00192
00193 if (sitter->socket_to_babysitter.sock != INVALID_SOCKET)
00194 {
00195 _dbus_close_socket (sitter->socket_to_babysitter, NULL);
00196 sitter->socket_to_babysitter.sock = INVALID_SOCKET;
00197 }
00198 }
00199
00205 void
00206 _dbus_babysitter_unref (DBusBabysitter *sitter)
00207 {
00208 int i;
00209 dbus_int32_t old_refcount;
00210
00211 PING();
00212 _dbus_assert (sitter != NULL);
00213
00214 old_refcount = _dbus_atomic_dec (&sitter->refcount);
00215 _dbus_assert (old_refcount > 0);
00216 _dbus_babysitter_trace_ref (sitter, old_refcount, old_refcount-1, __FUNCTION__);
00217
00218 if (old_refcount == 1)
00219 {
00220 close_socket_to_babysitter (sitter);
00221
00222 if (sitter->socket_to_main.sock != INVALID_SOCKET)
00223 {
00224 _dbus_close_socket (sitter->socket_to_main, NULL);
00225 sitter->socket_to_main.sock = INVALID_SOCKET;
00226 }
00227
00228 PING();
00229 if (sitter->argv != NULL)
00230 {
00231 for (i = 0; i < sitter->argc; i++)
00232 if (sitter->argv[i] != NULL)
00233 {
00234 dbus_free (sitter->argv[i]);
00235 sitter->argv[i] = NULL;
00236 }
00237 dbus_free (sitter->argv);
00238 sitter->argv = NULL;
00239 }
00240
00241 if (sitter->envp != NULL)
00242 {
00243 char **e = sitter->envp;
00244
00245 while (*e)
00246 dbus_free (*e++);
00247 dbus_free (sitter->envp);
00248 sitter->envp = NULL;
00249 }
00250
00251 if (sitter->child_handle != NULL)
00252 {
00253 CloseHandle (sitter->child_handle);
00254 sitter->child_handle = NULL;
00255 }
00256
00257 if (sitter->sitter_watch)
00258 {
00259 _dbus_watch_invalidate (sitter->sitter_watch);
00260 _dbus_watch_unref (sitter->sitter_watch);
00261 sitter->sitter_watch = NULL;
00262 }
00263
00264 if (sitter->watches)
00265 _dbus_watch_list_free (sitter->watches);
00266
00267 if (sitter->start_sync_event != NULL)
00268 {
00269 PING();
00270 CloseHandle (sitter->start_sync_event);
00271 sitter->start_sync_event = NULL;
00272 }
00273
00274 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00275 if (sitter->end_sync_event != NULL)
00276 {
00277 CloseHandle (sitter->end_sync_event);
00278 sitter->end_sync_event = NULL;
00279 }
00280 #endif
00281
00282 dbus_free (sitter->log_name);
00283
00284 dbus_free (sitter);
00285 }
00286 }
00287
00288 void
00289 _dbus_babysitter_kill_child (DBusBabysitter *sitter)
00290 {
00291 PING();
00292 if (sitter->child_handle == NULL)
00293 return;
00294
00295 PING();
00296 TerminateProcess (sitter->child_handle, 12345);
00297 }
00298
00304 dbus_bool_t
00305 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
00306 {
00307 PING();
00308 return (sitter->child_handle == NULL);
00309 }
00310
00323 dbus_bool_t
00324 _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter,
00325 int *status)
00326 {
00327 if (!_dbus_babysitter_get_child_exited (sitter))
00328 _dbus_assert_not_reached ("Child has not exited");
00329
00330 if (!sitter->have_child_status ||
00331 sitter->child_status == STILL_ACTIVE)
00332 return FALSE;
00333
00334 *status = sitter->child_status;
00335 return TRUE;
00336 }
00337
00347 void
00348 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
00349 DBusError *error)
00350 {
00351 PING();
00352 if (!_dbus_babysitter_get_child_exited (sitter))
00353 return;
00354
00355 PING();
00356 if (sitter->have_spawn_errno)
00357 {
00358 char *emsg = _dbus_win_error_string (sitter->spawn_errno);
00359 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
00360 "Failed to execute program %s: %s",
00361 sitter->log_name, emsg);
00362 _dbus_win_free_error_string (emsg);
00363 }
00364 else if (sitter->have_child_status)
00365 {
00366 PING();
00367 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
00368 "Process %s exited with status %d",
00369 sitter->log_name, sitter->child_status);
00370 }
00371 else
00372 {
00373 PING();
00374 dbus_set_error (error, DBUS_ERROR_FAILED,
00375 "Process %s exited, status unknown",
00376 sitter->log_name);
00377 }
00378 PING();
00379 }
00380
00381 dbus_bool_t
00382 _dbus_babysitter_set_watch_functions (DBusBabysitter *sitter,
00383 DBusAddWatchFunction add_function,
00384 DBusRemoveWatchFunction remove_function,
00385 DBusWatchToggledFunction toggled_function,
00386 void *data,
00387 DBusFreeFunction free_data_function)
00388 {
00389 PING();
00390 return _dbus_watch_list_set_functions (sitter->watches,
00391 add_function,
00392 remove_function,
00393 toggled_function,
00394 data,
00395 free_data_function);
00396 }
00397
00398 static dbus_bool_t
00399 handle_watch (DBusWatch *watch,
00400 unsigned int condition,
00401 void *data)
00402 {
00403 DBusBabysitter *sitter = data;
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415 PING();
00416 close_socket_to_babysitter (sitter);
00417 PING();
00418
00419 if (_dbus_babysitter_get_child_exited (sitter) &&
00420 sitter->finished_cb != NULL)
00421 {
00422 sitter->finished_cb (sitter, sitter->finished_data);
00423 sitter->finished_cb = NULL;
00424 }
00425
00426 return TRUE;
00427 }
00428
00429
00430 static int
00431 protect_argv (char **argv,
00432 char ***new_argv)
00433 {
00434 int i;
00435 int argc = 0;
00436
00437 while (argv[argc])
00438 ++argc;
00439 *new_argv = dbus_malloc ((argc + 1) * sizeof (char *));
00440 if (*new_argv == NULL)
00441 return -1;
00442
00443 for (i = 0; i < argc; i++)
00444 (*new_argv)[i] = NULL;
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457 for (i = 0; i < argc; i++)
00458 {
00459 char *p = argv[i];
00460 char *q;
00461 int len = 0;
00462 int need_dblquotes = FALSE;
00463 while (*p)
00464 {
00465 if (*p == ' ' || *p == '\t')
00466 need_dblquotes = TRUE;
00467 else if (*p == '"')
00468 len++;
00469 else if (*p == '\\')
00470 {
00471 char *pp = p;
00472 while (*pp && *pp == '\\')
00473 pp++;
00474 if (*pp == '"')
00475 len++;
00476 }
00477 len++;
00478 p++;
00479 }
00480
00481 q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1);
00482
00483 if (q == NULL)
00484 return -1;
00485
00486
00487 p = argv[i];
00488
00489 if (need_dblquotes)
00490 *q++ = '"';
00491
00492 while (*p)
00493 {
00494 if (*p == '"')
00495 *q++ = '\\';
00496 else if (*p == '\\')
00497 {
00498 char *pp = p;
00499 while (*pp && *pp == '\\')
00500 pp++;
00501 if (*pp == '"')
00502 *q++ = '\\';
00503 }
00504 *q++ = *p;
00505 p++;
00506 }
00507
00508 if (need_dblquotes)
00509 *q++ = '"';
00510 *q++ = '\0';
00511
00512 }
00513 (*new_argv)[argc] = NULL;
00514
00515 return argc;
00516 }
00517
00518
00519
00520 static char *
00521 compose_string (char **strings, char separator)
00522 {
00523 int i;
00524 int n = 0;
00525 char *buf;
00526 char *p;
00527
00528 if (!strings || !strings[0])
00529 return 0;
00530 for (i = 0; strings[i]; i++)
00531 n += strlen (strings[i]) + 1;
00532 n++;
00533
00534 buf = p = malloc (n);
00535 if (!buf)
00536 return NULL;
00537 for (i = 0; strings[i]; i++)
00538 {
00539 strcpy (p, strings[i]);
00540 p += strlen (strings[i]);
00541 *(p++) = separator;
00542 }
00543 p--;
00544 *(p++) = '\0';
00545 *p = '\0';
00546
00547 return buf;
00548 }
00549
00550 static char *
00551 build_commandline (char **argv)
00552 {
00553 return compose_string (argv, ' ');
00554 }
00555
00556 static char *
00557 build_env_string (char** envp)
00558 {
00559 return compose_string (envp, '\0');
00560 }
00561
00562 static HANDLE
00563 spawn_program (char* name, char** argv, char** envp)
00564 {
00565 PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
00566 STARTUPINFOA si;
00567 char *arg_string, *env_string;
00568 BOOL result;
00569
00570 #ifdef DBUS_WINCE
00571 if (argv && argv[0])
00572 arg_string = build_commandline (argv + 1);
00573 else
00574 arg_string = NULL;
00575 #else
00576 arg_string = build_commandline (argv);
00577 #endif
00578 if (!arg_string)
00579 return INVALID_HANDLE_VALUE;
00580
00581 env_string = build_env_string(envp);
00582
00583 memset (&si, 0, sizeof (si));
00584 si.cb = sizeof (si);
00585 #ifdef DBUS_WINCE
00586 result = CreateProcessA (name, arg_string, NULL, NULL, FALSE, 0,
00587 #else
00588 result = CreateProcessA (NULL, arg_string, NULL, NULL, FALSE, 0,
00589 #endif
00590 (LPVOID)env_string, NULL, &si, &pi);
00591 free (arg_string);
00592 if (env_string)
00593 free (env_string);
00594
00595 if (!result)
00596 return INVALID_HANDLE_VALUE;
00597
00598 CloseHandle (pi.hThread);
00599 return pi.hProcess;
00600 }
00601
00602
00603 static DWORD __stdcall
00604 babysitter (void *parameter)
00605 {
00606 int ret = 0;
00607 DBusBabysitter *sitter = (DBusBabysitter *) parameter;
00608 HANDLE handle;
00609
00610 PING();
00611 if (sitter->child_setup)
00612 {
00613 PING();
00614 (*sitter->child_setup) (sitter->user_data);
00615 }
00616
00617 _dbus_verbose ("babysitter: spawning %s\n", sitter->log_name);
00618
00619 PING();
00620 handle = spawn_program (sitter->log_name, sitter->argv, sitter->envp);
00621
00622 PING();
00623 if (handle != INVALID_HANDLE_VALUE)
00624 {
00625 sitter->child_handle = handle;
00626 }
00627 else
00628 {
00629 sitter->child_handle = NULL;
00630 sitter->have_spawn_errno = TRUE;
00631 sitter->spawn_errno = GetLastError();
00632 }
00633
00634 PING();
00635 SetEvent (sitter->start_sync_event);
00636
00637 if (sitter->child_handle != NULL)
00638 {
00639 DWORD status;
00640
00641 PING();
00642
00643 WaitForSingleObject (sitter->child_handle, INFINITE);
00644
00645 PING();
00646 ret = GetExitCodeProcess (sitter->child_handle, &status);
00647 if (ret)
00648 {
00649 sitter->child_status = status;
00650 sitter->have_child_status = TRUE;
00651 }
00652
00653 CloseHandle (sitter->child_handle);
00654 sitter->child_handle = NULL;
00655 }
00656
00657 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00658 SetEvent (sitter->end_sync_event);
00659 #endif
00660
00661 PING();
00662 send (sitter->socket_to_main.sock, " ", 1, 0);
00663
00664 _dbus_babysitter_unref (sitter);
00665
00666 return ret ? 0 : 1;
00667 }
00668
00669 dbus_bool_t
00670 _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
00671 const char *log_name,
00672 char **argv,
00673 char **envp,
00674 DBusSpawnChildSetupFunc child_setup,
00675 void *user_data,
00676 DBusError *error)
00677 {
00678 DBusBabysitter *sitter;
00679 HANDLE sitter_thread;
00680 DWORD sitter_thread_id;
00681
00682 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00683 _dbus_assert (argv[0] != NULL);
00684
00685 if (sitter_p != NULL)
00686 *sitter_p = NULL;
00687
00688 PING();
00689 sitter = _dbus_babysitter_new ();
00690 if (sitter == NULL)
00691 {
00692 _DBUS_SET_OOM (error);
00693 return FALSE;
00694 }
00695
00696 sitter->child_setup = child_setup;
00697 sitter->user_data = user_data;
00698
00699 sitter->log_name = _dbus_strdup (log_name);
00700 if (sitter->log_name == NULL && log_name != NULL)
00701 {
00702 _DBUS_SET_OOM (error);
00703 goto out0;
00704 }
00705
00706 if (sitter->log_name == NULL)
00707 sitter->log_name = _dbus_strdup (argv[0]);
00708
00709 if (sitter->log_name == NULL)
00710 {
00711 _DBUS_SET_OOM (error);
00712 goto out0;
00713 }
00714
00715 PING();
00716 if (!_dbus_socketpair (&sitter->socket_to_babysitter,
00717 &sitter->socket_to_main,
00718 FALSE, error))
00719 goto out0;
00720
00721 sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter,
00722 DBUS_WATCH_READABLE,
00723 TRUE, handle_watch, sitter, NULL);
00724 PING();
00725 if (sitter->sitter_watch == NULL)
00726 {
00727 _DBUS_SET_OOM (error);
00728 goto out0;
00729 }
00730
00731 PING();
00732 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
00733 {
00734
00735
00736 _dbus_watch_invalidate (sitter->sitter_watch);
00737 _dbus_watch_unref (sitter->sitter_watch);
00738 sitter->sitter_watch = NULL;
00739
00740 _DBUS_SET_OOM (error);
00741 goto out0;
00742 }
00743
00744 sitter->argc = protect_argv (argv, &sitter->argv);
00745 if (sitter->argc == -1)
00746 {
00747 _DBUS_SET_OOM (error);
00748 goto out0;
00749 }
00750 sitter->envp = envp;
00751
00752 PING();
00753 sitter_thread = (HANDLE) CreateThread (NULL, 0, babysitter,
00754 _dbus_babysitter_ref (sitter), 0, &sitter_thread_id);
00755
00756 if (sitter_thread == 0)
00757 {
00758 PING();
00759 dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED,
00760 "Failed to create new thread");
00761 goto out0;
00762 }
00763 CloseHandle (sitter_thread);
00764
00765 PING();
00766 WaitForSingleObject (sitter->start_sync_event, INFINITE);
00767
00768 PING();
00769 if (sitter_p != NULL)
00770 *sitter_p = sitter;
00771 else
00772 _dbus_babysitter_unref (sitter);
00773
00774 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00775
00776 PING();
00777 return TRUE;
00778
00779 out0:
00780 _dbus_babysitter_unref (sitter);
00781
00782 return FALSE;
00783 }
00784
00785 void
00786 _dbus_babysitter_set_result_function (DBusBabysitter *sitter,
00787 DBusBabysitterFinishedFunc finished,
00788 void *user_data)
00789 {
00790 sitter->finished_cb = finished;
00791 sitter->finished_data = user_data;
00792 }
00793
00794 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00795
00796 static char *
00797 get_test_exec (const char *exe,
00798 DBusString *scratch_space)
00799 {
00800 const char *dbus_test_exec;
00801
00802 dbus_test_exec = _dbus_getenv ("DBUS_TEST_EXEC");
00803
00804 if (dbus_test_exec == NULL)
00805 dbus_test_exec = DBUS_TEST_EXEC;
00806
00807 if (!_dbus_string_init (scratch_space))
00808 return NULL;
00809
00810 if (!_dbus_string_append_printf (scratch_space, "%s/%s%s",
00811 dbus_test_exec, exe, DBUS_EXEEXT))
00812 {
00813 _dbus_string_free (scratch_space);
00814 return NULL;
00815 }
00816
00817 return _dbus_string_get_data (scratch_space);
00818 }
00819
00820 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)
00821
00822 static void
00823 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
00824 {
00825 if (sitter->child_handle == NULL)
00826 return;
00827
00828 WaitForSingleObject (sitter->end_sync_event, INFINITE);
00829 }
00830
00831 static dbus_bool_t
00832 check_spawn_nonexistent (void *data)
00833 {
00834 char *argv[4] = { NULL, NULL, NULL, NULL };
00835 DBusBabysitter *sitter;
00836 DBusError error;
00837
00838 sitter = NULL;
00839
00840 dbus_error_init (&error);
00841
00842
00843
00844 argv[0] = "/this/does/not/exist/32542sdgafgafdg";
00845 if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_nonexistent", argv, NULL,
00846 NULL, NULL,
00847 &error))
00848 {
00849 _dbus_babysitter_block_for_child_exit (sitter);
00850 _dbus_babysitter_set_child_exit_error (sitter, &error);
00851 }
00852
00853 if (sitter)
00854 _dbus_babysitter_unref (sitter);
00855
00856 if (!dbus_error_is_set (&error))
00857 {
00858 _dbus_warn ("Did not get an error launching nonexistent executable\n");
00859 return FALSE;
00860 }
00861
00862 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00863 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
00864 {
00865 _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
00866 error.name, error.message);
00867 dbus_error_free (&error);
00868 return FALSE;
00869 }
00870
00871 dbus_error_free (&error);
00872
00873 return TRUE;
00874 }
00875
00876 static dbus_bool_t
00877 check_spawn_segfault (void *data)
00878 {
00879 char *argv[4] = { NULL, NULL, NULL, NULL };
00880 DBusBabysitter *sitter;
00881 DBusError error;
00882 DBusString argv0;
00883
00884 sitter = NULL;
00885
00886 dbus_error_init (&error);
00887
00888
00889
00890 argv[0] = get_test_exec ("test-segfault", &argv0);
00891
00892 if (argv[0] == NULL)
00893 {
00894
00895 return TRUE;
00896 }
00897
00898 if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_segfault", argv, NULL,
00899 NULL, NULL,
00900 &error))
00901 {
00902 _dbus_babysitter_block_for_child_exit (sitter);
00903 _dbus_babysitter_set_child_exit_error (sitter, &error);
00904 }
00905
00906 _dbus_string_free (&argv0);
00907
00908 if (sitter)
00909 _dbus_babysitter_unref (sitter);
00910
00911 if (!dbus_error_is_set (&error))
00912 {
00913 _dbus_warn ("Did not get an error launching segfaulting binary\n");
00914 return FALSE;
00915 }
00916
00917 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00918 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
00919 {
00920 _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
00921 error.name, error.message);
00922 dbus_error_free (&error);
00923 return FALSE;
00924 }
00925
00926 dbus_error_free (&error);
00927
00928 return TRUE;
00929 }
00930
00931 static dbus_bool_t
00932 check_spawn_exit (void *data)
00933 {
00934 char *argv[4] = { NULL, NULL, NULL, NULL };
00935 DBusBabysitter *sitter;
00936 DBusError error;
00937 DBusString argv0;
00938
00939 sitter = NULL;
00940
00941 dbus_error_init (&error);
00942
00943
00944
00945 argv[0] = get_test_exec ("test-exit", &argv0);
00946
00947 if (argv[0] == NULL)
00948 {
00949
00950 return TRUE;
00951 }
00952
00953 if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_exit", argv, NULL,
00954 NULL, NULL,
00955 &error))
00956 {
00957 _dbus_babysitter_block_for_child_exit (sitter);
00958 _dbus_babysitter_set_child_exit_error (sitter, &error);
00959 }
00960
00961 _dbus_string_free (&argv0);
00962
00963 if (sitter)
00964 _dbus_babysitter_unref (sitter);
00965
00966 if (!dbus_error_is_set (&error))
00967 {
00968 _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
00969 return FALSE;
00970 }
00971
00972 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00973 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
00974 {
00975 _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
00976 error.name, error.message);
00977 dbus_error_free (&error);
00978 return FALSE;
00979 }
00980
00981 dbus_error_free (&error);
00982
00983 return TRUE;
00984 }
00985
00986 static dbus_bool_t
00987 check_spawn_and_kill (void *data)
00988 {
00989 char *argv[4] = { NULL, NULL, NULL, NULL };
00990 DBusBabysitter *sitter;
00991 DBusError error;
00992 DBusString argv0;
00993
00994 sitter = NULL;
00995
00996 dbus_error_init (&error);
00997
00998
00999
01000 argv[0] = get_test_exec ("test-sleep-forever", &argv0);
01001
01002 if (argv[0] == NULL)
01003 {
01004
01005 return TRUE;
01006 }
01007
01008 if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_and_kill", argv, NULL,
01009 NULL, NULL,
01010 &error))
01011 {
01012 _dbus_babysitter_kill_child (sitter);
01013
01014 _dbus_babysitter_block_for_child_exit (sitter);
01015
01016 _dbus_babysitter_set_child_exit_error (sitter, &error);
01017 }
01018
01019 _dbus_string_free (&argv0);
01020
01021 if (sitter)
01022 _dbus_babysitter_unref (sitter);
01023
01024 if (!dbus_error_is_set (&error))
01025 {
01026 _dbus_warn ("Did not get an error after killing spawned binary\n");
01027 return FALSE;
01028 }
01029
01030 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
01031 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
01032 {
01033 _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
01034 error.name, error.message);
01035 dbus_error_free (&error);
01036 return FALSE;
01037 }
01038
01039 dbus_error_free (&error);
01040
01041 return TRUE;
01042 }
01043
01044 dbus_bool_t
01045 _dbus_spawn_test (const char *test_data_dir)
01046 {
01047 if (!_dbus_test_oom_handling ("spawn_nonexistent",
01048 check_spawn_nonexistent,
01049 NULL))
01050 return FALSE;
01051
01052
01053
01054
01055 if (getenv ("DO_SEGFAULT_TEST"))
01056 if (!_dbus_test_oom_handling ("spawn_segfault",
01057 check_spawn_segfault,
01058 NULL))
01059 return FALSE;
01060
01061 if (!_dbus_test_oom_handling ("spawn_exit",
01062 check_spawn_exit,
01063 NULL))
01064 return FALSE;
01065
01066 if (!_dbus_test_oom_handling ("spawn_and_kill",
01067 check_spawn_and_kill,
01068 NULL))
01069 return FALSE;
01070
01071 return TRUE;
01072 }
01073 #endif