|
D-Bus
1.5.8
|
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 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; /* child is already dead, or we're so hosed we'll never recover */ 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 /* On Unix dbus-spawn uses a babysitter *process*, thus it has to 00384 * actually send the exit statuses, error codes and whatnot through 00385 * sockets and/or pipes. On Win32, the babysitter is jus a thread, 00386 * so it can set the status fields directly in the babysitter struct 00387 * just fine. The socket pipe is used just so we can watch it with 00388 * select(), as soon as anything is written to it we know that the 00389 * babysitter thread has recorded the status in the babysitter 00390 * struct. 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 /* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */ 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 /* Quote each argv element if necessary, so that it will get 00425 * reconstructed correctly in the C runtime startup code. Note that 00426 * the unquoting algorithm in the C runtime is really weird, and 00427 * rather different than what Unix shells do. See stdargv.c in the C 00428 * runtime sources (in the Platform SDK, in src/crt). 00429 * 00430 * Note that an new_argv[0] constructed by this function should 00431 * *not* be passed as the filename argument to a spawn* or exec* 00432 * family function. That argument should be the real file name 00433 * without any quoting. 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 /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */ 00490 } 00491 (*new_argv)[argc] = NULL; 00492 00493 return argc; 00494 } 00495 00496 00497 /* From GPGME, relicensed by g10 Code GmbH. */ 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 00506 if (!strings || !strings[0]) 00507 return 0; 00508 for (i = 0; strings[i]; i++) 00509 n += strlen (strings[i]) + 1; 00510 n++; 00511 00512 buf = p = malloc (n); 00513 if (!buf) 00514 return NULL; 00515 for (i = 0; strings[i]; i++) 00516 { 00517 strcpy (p, strings[i]); 00518 p += strlen (strings[i]); 00519 *(p++) = separator; 00520 } 00521 p--; 00522 *(p++) = '\0'; 00523 *p = '\0'; 00524 00525 return buf; 00526 } 00527 00528 static char * 00529 build_commandline (char **argv) 00530 { 00531 return compose_string (argv, ' '); 00532 } 00533 00534 static char * 00535 build_env_string (char** envp) 00536 { 00537 return compose_string (envp, '\0'); 00538 } 00539 00540 static HANDLE 00541 spawn_program (char* name, char** argv, char** envp) 00542 { 00543 PROCESS_INFORMATION pi = { NULL, 0, 0, 0 }; 00544 STARTUPINFOA si; 00545 char *arg_string, *env_string; 00546 BOOL result; 00547 00548 #ifdef DBUS_WINCE 00549 if (argv && argv[0]) 00550 arg_string = build_commandline (argv + 1); 00551 else 00552 arg_string = NULL; 00553 #else 00554 arg_string = build_commandline (argv); 00555 #endif 00556 if (!arg_string) 00557 return INVALID_HANDLE_VALUE; 00558 00559 env_string = build_env_string(envp); 00560 00561 memset (&si, 0, sizeof (si)); 00562 si.cb = sizeof (si); 00563 #ifdef DBUS_WINCE 00564 result = CreateProcessA (name, arg_string, NULL, NULL, FALSE, 0, 00565 #else 00566 result = CreateProcessA (NULL, arg_string, NULL, NULL, FALSE, 0, 00567 #endif 00568 (LPVOID)env_string, NULL, &si, &pi); 00569 free (arg_string); 00570 if (env_string) 00571 free (env_string); 00572 00573 if (!result) 00574 return INVALID_HANDLE_VALUE; 00575 00576 CloseHandle (pi.hThread); 00577 return pi.hProcess; 00578 } 00579 00580 00581 static DWORD __stdcall 00582 babysitter (void *parameter) 00583 { 00584 DBusBabysitter *sitter = (DBusBabysitter *) parameter; 00585 00586 PING(); 00587 _dbus_babysitter_ref (sitter); 00588 00589 if (sitter->child_setup) 00590 { 00591 PING(); 00592 (*sitter->child_setup) (sitter->user_data); 00593 } 00594 00595 _dbus_verbose ("babysitter: spawning %s\n", sitter->executable); 00596 00597 PING(); 00598 sitter->child_handle = spawn_program (sitter->executable, 00599 sitter->argv, sitter->envp); 00600 00601 PING(); 00602 if (sitter->child_handle == (HANDLE) -1) 00603 { 00604 sitter->child_handle = NULL; 00605 sitter->have_spawn_errno = TRUE; 00606 sitter->spawn_errno = GetLastError(); 00607 } 00608 00609 PING(); 00610 SetEvent (sitter->start_sync_event); 00611 00612 if (sitter->child_handle != NULL) 00613 { 00614 int ret; 00615 DWORD status; 00616 00617 PING(); 00618 WaitForSingleObject (sitter->child_handle, INFINITE); 00619 00620 PING(); 00621 ret = GetExitCodeProcess (sitter->child_handle, &status); 00622 00623 sitter->child_status = status; 00624 sitter->have_child_status = TRUE; 00625 00626 CloseHandle (sitter->child_handle); 00627 sitter->child_handle = NULL; 00628 } 00629 00630 #ifdef DBUS_BUILD_TESTS 00631 SetEvent (sitter->end_sync_event); 00632 #endif 00633 00634 PING(); 00635 send (sitter->socket_to_main, " ", 1, 0); 00636 00637 _dbus_babysitter_unref (sitter); 00638 00639 return 0; 00640 } 00641 00642 dbus_bool_t 00643 _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p, 00644 char **argv, 00645 char **envp, 00646 DBusSpawnChildSetupFunc child_setup, 00647 void *user_data, 00648 DBusError *error) 00649 { 00650 DBusBabysitter *sitter; 00651 HANDLE sitter_thread; 00652 DWORD sitter_thread_id; 00653 00654 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00655 00656 *sitter_p = NULL; 00657 00658 PING(); 00659 sitter = _dbus_babysitter_new (); 00660 if (sitter == NULL) 00661 { 00662 _DBUS_SET_OOM (error); 00663 return FALSE; 00664 } 00665 00666 sitter->child_setup = child_setup; 00667 sitter->user_data = user_data; 00668 00669 sitter->executable = _dbus_strdup (argv[0]); 00670 if (sitter->executable == NULL) 00671 { 00672 _DBUS_SET_OOM (error); 00673 goto out0; 00674 } 00675 00676 PING(); 00677 if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter, 00678 &sitter->socket_to_main, 00679 FALSE, error)) 00680 goto out0; 00681 00682 sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter, 00683 DBUS_WATCH_READABLE, 00684 TRUE, handle_watch, sitter, NULL); 00685 PING(); 00686 if (sitter->sitter_watch == NULL) 00687 { 00688 _DBUS_SET_OOM (error); 00689 goto out0; 00690 } 00691 00692 PING(); 00693 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch)) 00694 { 00695 /* we need to free it early so the destructor won't try to remove it 00696 * without it having been added, which DBusLoop doesn't allow */ 00697 _dbus_watch_invalidate (sitter->sitter_watch); 00698 _dbus_watch_unref (sitter->sitter_watch); 00699 sitter->sitter_watch = NULL; 00700 00701 _DBUS_SET_OOM (error); 00702 goto out0; 00703 } 00704 00705 sitter->argc = protect_argv (argv, &sitter->argv); 00706 if (sitter->argc == -1) 00707 { 00708 _DBUS_SET_OOM (error); 00709 goto out0; 00710 } 00711 sitter->envp = envp; 00712 00713 PING(); 00714 sitter_thread = (HANDLE) CreateThread (NULL, 0, babysitter, 00715 sitter, 0, &sitter_thread_id); 00716 00717 if (sitter_thread == 0) 00718 { 00719 PING(); 00720 dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED, 00721 "Failed to create new thread"); 00722 goto out0; 00723 } 00724 CloseHandle (sitter_thread); 00725 00726 PING(); 00727 WaitForSingleObject (sitter->start_sync_event, INFINITE); 00728 00729 PING(); 00730 if (sitter_p != NULL) 00731 *sitter_p = sitter; 00732 else 00733 _dbus_babysitter_unref (sitter); 00734 00735 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00736 00737 PING(); 00738 return TRUE; 00739 00740 out0: 00741 _dbus_babysitter_unref (sitter); 00742 00743 return FALSE; 00744 } 00745 00746 void 00747 _dbus_babysitter_set_result_function (DBusBabysitter *sitter, 00748 DBusBabysitterFinishedFunc finished, 00749 void *user_data) 00750 { 00751 sitter->finished_cb = finished; 00752 sitter->finished_data = user_data; 00753 } 00754 00755 #ifdef DBUS_BUILD_TESTS 00756 00757 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL) 00758 00759 static void 00760 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter) 00761 { 00762 if (sitter->child_handle == NULL) 00763 return; 00764 00765 WaitForSingleObject (sitter->end_sync_event, INFINITE); 00766 } 00767 00768 static dbus_bool_t 00769 check_spawn_nonexistent (void *data) 00770 { 00771 char *argv[4] = { NULL, NULL, NULL, NULL }; 00772 DBusBabysitter *sitter; 00773 DBusError error; 00774 00775 sitter = NULL; 00776 00777 dbus_error_init (&error); 00778 00779 /*** Test launching nonexistent binary */ 00780 00781 argv[0] = "/this/does/not/exist/32542sdgafgafdg"; 00782 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, 00783 NULL, NULL, 00784 &error)) 00785 { 00786 _dbus_babysitter_block_for_child_exit (sitter); 00787 _dbus_babysitter_set_child_exit_error (sitter, &error); 00788 } 00789 00790 if (sitter) 00791 _dbus_babysitter_unref (sitter); 00792 00793 if (!dbus_error_is_set (&error)) 00794 { 00795 _dbus_warn ("Did not get an error launching nonexistent executable\n"); 00796 return FALSE; 00797 } 00798 00799 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 00800 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED))) 00801 { 00802 _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n", 00803 error.name, error.message); 00804 dbus_error_free (&error); 00805 return FALSE; 00806 } 00807 00808 dbus_error_free (&error); 00809 00810 return TRUE; 00811 } 00812 00813 static dbus_bool_t 00814 check_spawn_segfault (void *data) 00815 { 00816 char *argv[4] = { NULL, NULL, NULL, NULL }; 00817 DBusBabysitter *sitter; 00818 DBusError error; 00819 00820 sitter = NULL; 00821 00822 dbus_error_init (&error); 00823 00824 /*** Test launching segfault binary */ 00825 00826 argv[0] = TEST_SEGFAULT_BINARY; 00827 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, 00828 NULL, NULL, 00829 &error)) 00830 { 00831 _dbus_babysitter_block_for_child_exit (sitter); 00832 _dbus_babysitter_set_child_exit_error (sitter, &error); 00833 } 00834 00835 if (sitter) 00836 _dbus_babysitter_unref (sitter); 00837 00838 if (!dbus_error_is_set (&error)) 00839 { 00840 _dbus_warn ("Did not get an error launching segfaulting binary\n"); 00841 return FALSE; 00842 } 00843 00844 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 00845 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) 00846 { 00847 _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n", 00848 error.name, error.message); 00849 dbus_error_free (&error); 00850 return FALSE; 00851 } 00852 00853 dbus_error_free (&error); 00854 00855 return TRUE; 00856 } 00857 00858 static dbus_bool_t 00859 check_spawn_exit (void *data) 00860 { 00861 char *argv[4] = { NULL, NULL, NULL, NULL }; 00862 DBusBabysitter *sitter; 00863 DBusError error; 00864 00865 sitter = NULL; 00866 00867 dbus_error_init (&error); 00868 00869 /*** Test launching exit failure binary */ 00870 00871 argv[0] = TEST_EXIT_BINARY; 00872 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, 00873 NULL, NULL, 00874 &error)) 00875 { 00876 _dbus_babysitter_block_for_child_exit (sitter); 00877 _dbus_babysitter_set_child_exit_error (sitter, &error); 00878 } 00879 00880 if (sitter) 00881 _dbus_babysitter_unref (sitter); 00882 00883 if (!dbus_error_is_set (&error)) 00884 { 00885 _dbus_warn ("Did not get an error launching binary that exited with failure code\n"); 00886 return FALSE; 00887 } 00888 00889 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 00890 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) 00891 { 00892 _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n", 00893 error.name, error.message); 00894 dbus_error_free (&error); 00895 return FALSE; 00896 } 00897 00898 dbus_error_free (&error); 00899 00900 return TRUE; 00901 } 00902 00903 static dbus_bool_t 00904 check_spawn_and_kill (void *data) 00905 { 00906 char *argv[4] = { NULL, NULL, NULL, NULL }; 00907 DBusBabysitter *sitter; 00908 DBusError error; 00909 00910 sitter = NULL; 00911 00912 dbus_error_init (&error); 00913 00914 /*** Test launching sleeping binary then killing it */ 00915 00916 argv[0] = TEST_SLEEP_FOREVER_BINARY; 00917 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL, 00918 NULL, NULL, 00919 &error)) 00920 { 00921 _dbus_babysitter_kill_child (sitter); 00922 00923 _dbus_babysitter_block_for_child_exit (sitter); 00924 00925 _dbus_babysitter_set_child_exit_error (sitter, &error); 00926 } 00927 00928 if (sitter) 00929 _dbus_babysitter_unref (sitter); 00930 00931 if (!dbus_error_is_set (&error)) 00932 { 00933 _dbus_warn ("Did not get an error after killing spawned binary\n"); 00934 return FALSE; 00935 } 00936 00937 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 00938 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) 00939 { 00940 _dbus_warn ("Not expecting error when killing executable: %s: %s\n", 00941 error.name, error.message); 00942 dbus_error_free (&error); 00943 return FALSE; 00944 } 00945 00946 dbus_error_free (&error); 00947 00948 return TRUE; 00949 } 00950 00951 dbus_bool_t 00952 _dbus_spawn_test (const char *test_data_dir) 00953 { 00954 if (!_dbus_test_oom_handling ("spawn_nonexistent", 00955 check_spawn_nonexistent, 00956 NULL)) 00957 return FALSE; 00958 00959 /* Don't run the obnoxious segfault test by default, 00960 * it's a pain to have to click all those error boxes. 00961 */ 00962 if (getenv ("DO_SEGFAULT_TEST")) 00963 if (!_dbus_test_oom_handling ("spawn_segfault", 00964 check_spawn_segfault, 00965 NULL)) 00966 return FALSE; 00967 00968 if (!_dbus_test_oom_handling ("spawn_exit", 00969 check_spawn_exit, 00970 NULL)) 00971 return FALSE; 00972 00973 if (!_dbus_test_oom_handling ("spawn_and_kill", 00974 check_spawn_and_kill, 00975 NULL)) 00976 return FALSE; 00977 00978 return TRUE; 00979 } 00980 #endif
1.7.5.1