|
D-Bus
1.8.20
|
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 #include <windows.h> 00046 //#define STRICT 00047 //#include <windows.h> 00048 //#undef STRICT 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_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 int socket_to_babysitter; /* Connection to the babysitter thread */ 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_ENABLE_EMBEDDED_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_ENABLE_EMBEDDED_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->log_name); 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; /* child is already dead, or we're so hosed we'll never recover */ 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->log_name, 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->log_name, 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->log_name); 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 /* On Unix dbus-spawn uses a babysitter *process*, thus it has to 00385 * actually send the exit statuses, error codes and whatnot through 00386 * sockets and/or pipes. On Win32, the babysitter is jus a thread, 00387 * so it can set the status fields directly in the babysitter struct 00388 * just fine. The socket pipe is used just so we can watch it with 00389 * select(), as soon as anything is written to it we know that the 00390 * babysitter thread has recorded the status in the babysitter 00391 * struct. 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 /* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */ 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 /* Quote each argv element if necessary, so that it will get 00426 * reconstructed correctly in the C runtime startup code. Note that 00427 * the unquoting algorithm in the C runtime is really weird, and 00428 * rather different than what Unix shells do. See stdargv.c in the C 00429 * runtime sources (in the Platform SDK, in src/crt). 00430 * 00431 * Note that an new_argv[0] constructed by this function should 00432 * *not* be passed as the filename argument to a spawn* or exec* 00433 * family function. That argument should be the real file name 00434 * without any quoting. 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 /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */ 00491 } 00492 (*new_argv)[argc] = NULL; 00493 00494 return argc; 00495 } 00496 00497 00498 /* From GPGME, relicensed by g10 Code GmbH. */ 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->log_name); 00597 00598 PING(); 00599 sitter->child_handle = spawn_program (sitter->log_name, 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_ENABLE_EMBEDDED_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 const char *log_name, 00646 char **argv, 00647 char **envp, 00648 DBusSpawnChildSetupFunc child_setup, 00649 void *user_data, 00650 DBusError *error) 00651 { 00652 DBusBabysitter *sitter; 00653 HANDLE sitter_thread; 00654 DWORD sitter_thread_id; 00655 00656 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00657 _dbus_assert (argv[0] != NULL); 00658 00659 *sitter_p = NULL; 00660 00661 PING(); 00662 sitter = _dbus_babysitter_new (); 00663 if (sitter == NULL) 00664 { 00665 _DBUS_SET_OOM (error); 00666 return FALSE; 00667 } 00668 00669 sitter->child_setup = child_setup; 00670 sitter->user_data = user_data; 00671 00672 sitter->log_name = _dbus_strdup (log_name); 00673 if (sitter->log_name == NULL && log_name != NULL) 00674 { 00675 _DBUS_SET_OOM (error); 00676 goto out0; 00677 } 00678 00679 if (sitter->log_name == NULL) 00680 sitter->log_name = _dbus_strdup (argv[0]); 00681 00682 if (sitter->log_name == NULL) 00683 { 00684 _DBUS_SET_OOM (error); 00685 goto out0; 00686 } 00687 00688 PING(); 00689 if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter, 00690 &sitter->socket_to_main, 00691 FALSE, error)) 00692 goto out0; 00693 00694 sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter, 00695 DBUS_WATCH_READABLE, 00696 TRUE, handle_watch, sitter, NULL); 00697 PING(); 00698 if (sitter->sitter_watch == NULL) 00699 { 00700 _DBUS_SET_OOM (error); 00701 goto out0; 00702 } 00703 00704 PING(); 00705 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch)) 00706 { 00707 /* we need to free it early so the destructor won't try to remove it 00708 * without it having been added, which DBusLoop doesn't allow */ 00709 _dbus_watch_invalidate (sitter->sitter_watch); 00710 _dbus_watch_unref (sitter->sitter_watch); 00711 sitter->sitter_watch = NULL; 00712 00713 _DBUS_SET_OOM (error); 00714 goto out0; 00715 } 00716 00717 sitter->argc = protect_argv (argv, &sitter->argv); 00718 if (sitter->argc == -1) 00719 { 00720 _DBUS_SET_OOM (error); 00721 goto out0; 00722 } 00723 sitter->envp = envp; 00724 00725 PING(); 00726 sitter_thread = (HANDLE) CreateThread (NULL, 0, babysitter, 00727 sitter, 0, &sitter_thread_id); 00728 00729 if (sitter_thread == 0) 00730 { 00731 PING(); 00732 dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED, 00733 "Failed to create new thread"); 00734 goto out0; 00735 } 00736 CloseHandle (sitter_thread); 00737 00738 PING(); 00739 WaitForSingleObject (sitter->start_sync_event, INFINITE); 00740 00741 PING(); 00742 if (sitter_p != NULL) 00743 *sitter_p = sitter; 00744 else 00745 _dbus_babysitter_unref (sitter); 00746 00747 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00748 00749 PING(); 00750 return TRUE; 00751 00752 out0: 00753 _dbus_babysitter_unref (sitter); 00754 00755 return FALSE; 00756 } 00757 00758 void 00759 _dbus_babysitter_set_result_function (DBusBabysitter *sitter, 00760 DBusBabysitterFinishedFunc finished, 00761 void *user_data) 00762 { 00763 sitter->finished_cb = finished; 00764 sitter->finished_data = user_data; 00765 } 00766 00767 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 00768 00769 static char * 00770 get_test_exec (const char *exe, 00771 DBusString *scratch_space) 00772 { 00773 const char *dbus_test_exec; 00774 00775 dbus_test_exec = _dbus_getenv ("DBUS_TEST_EXEC"); 00776 00777 if (dbus_test_exec == NULL) 00778 dbus_test_exec = DBUS_TEST_EXEC; 00779 00780 if (!_dbus_string_init (scratch_space)) 00781 return NULL; 00782 00783 if (!_dbus_string_append_printf (scratch_space, "%s/%s%s", 00784 dbus_test_exec, exe, DBUS_EXEEXT)) 00785 { 00786 _dbus_string_free (scratch_space); 00787 return NULL; 00788 } 00789 00790 return _dbus_string_get_data (scratch_space); 00791 } 00792 00793 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL) 00794 00795 static void 00796 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter) 00797 { 00798 if (sitter->child_handle == NULL) 00799 return; 00800 00801 WaitForSingleObject (sitter->end_sync_event, INFINITE); 00802 } 00803 00804 static dbus_bool_t 00805 check_spawn_nonexistent (void *data) 00806 { 00807 char *argv[4] = { NULL, NULL, NULL, NULL }; 00808 DBusBabysitter *sitter; 00809 DBusError error; 00810 00811 sitter = NULL; 00812 00813 dbus_error_init (&error); 00814 00815 /*** Test launching nonexistent binary */ 00816 00817 argv[0] = "/this/does/not/exist/32542sdgafgafdg"; 00818 if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_nonexistent", argv, NULL, 00819 NULL, NULL, 00820 &error)) 00821 { 00822 _dbus_babysitter_block_for_child_exit (sitter); 00823 _dbus_babysitter_set_child_exit_error (sitter, &error); 00824 } 00825 00826 if (sitter) 00827 _dbus_babysitter_unref (sitter); 00828 00829 if (!dbus_error_is_set (&error)) 00830 { 00831 _dbus_warn ("Did not get an error launching nonexistent executable\n"); 00832 return FALSE; 00833 } 00834 00835 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 00836 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED))) 00837 { 00838 _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n", 00839 error.name, error.message); 00840 dbus_error_free (&error); 00841 return FALSE; 00842 } 00843 00844 dbus_error_free (&error); 00845 00846 return TRUE; 00847 } 00848 00849 static dbus_bool_t 00850 check_spawn_segfault (void *data) 00851 { 00852 char *argv[4] = { NULL, NULL, NULL, NULL }; 00853 DBusBabysitter *sitter; 00854 DBusError error; 00855 DBusString argv0; 00856 00857 sitter = NULL; 00858 00859 dbus_error_init (&error); 00860 00861 /*** Test launching segfault binary */ 00862 00863 argv[0] = get_test_exec ("test-segfault", &argv0); 00864 00865 if (argv[0] == NULL) 00866 { 00867 /* OOM was simulated, never mind */ 00868 return TRUE; 00869 } 00870 00871 if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_segfault", argv, NULL, 00872 NULL, NULL, 00873 &error)) 00874 { 00875 _dbus_babysitter_block_for_child_exit (sitter); 00876 _dbus_babysitter_set_child_exit_error (sitter, &error); 00877 } 00878 00879 _dbus_string_free (&argv0); 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 segfaulting binary\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 segfaulting 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_exit (void *data) 00906 { 00907 char *argv[4] = { NULL, NULL, NULL, NULL }; 00908 DBusBabysitter *sitter; 00909 DBusError error; 00910 DBusString argv0; 00911 00912 sitter = NULL; 00913 00914 dbus_error_init (&error); 00915 00916 /*** Test launching exit failure binary */ 00917 00918 argv[0] = get_test_exec ("test-exit", &argv0); 00919 00920 if (argv[0] == NULL) 00921 { 00922 /* OOM was simulated, never mind */ 00923 return TRUE; 00924 } 00925 00926 if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_exit", argv, NULL, 00927 NULL, NULL, 00928 &error)) 00929 { 00930 _dbus_babysitter_block_for_child_exit (sitter); 00931 _dbus_babysitter_set_child_exit_error (sitter, &error); 00932 } 00933 00934 _dbus_string_free (&argv0); 00935 00936 if (sitter) 00937 _dbus_babysitter_unref (sitter); 00938 00939 if (!dbus_error_is_set (&error)) 00940 { 00941 _dbus_warn ("Did not get an error launching binary that exited with failure code\n"); 00942 return FALSE; 00943 } 00944 00945 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 00946 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) 00947 { 00948 _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n", 00949 error.name, error.message); 00950 dbus_error_free (&error); 00951 return FALSE; 00952 } 00953 00954 dbus_error_free (&error); 00955 00956 return TRUE; 00957 } 00958 00959 static dbus_bool_t 00960 check_spawn_and_kill (void *data) 00961 { 00962 char *argv[4] = { NULL, NULL, NULL, NULL }; 00963 DBusBabysitter *sitter; 00964 DBusError error; 00965 DBusString argv0; 00966 00967 sitter = NULL; 00968 00969 dbus_error_init (&error); 00970 00971 /*** Test launching sleeping binary then killing it */ 00972 00973 argv[0] = get_test_exec ("test-sleep-forever", &argv0); 00974 00975 if (argv[0] == NULL) 00976 { 00977 /* OOM was simulated, never mind */ 00978 return TRUE; 00979 } 00980 00981 if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_and_kill", argv, NULL, 00982 NULL, NULL, 00983 &error)) 00984 { 00985 _dbus_babysitter_kill_child (sitter); 00986 00987 _dbus_babysitter_block_for_child_exit (sitter); 00988 00989 _dbus_babysitter_set_child_exit_error (sitter, &error); 00990 } 00991 00992 _dbus_string_free (&argv0); 00993 00994 if (sitter) 00995 _dbus_babysitter_unref (sitter); 00996 00997 if (!dbus_error_is_set (&error)) 00998 { 00999 _dbus_warn ("Did not get an error after killing spawned binary\n"); 01000 return FALSE; 01001 } 01002 01003 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || 01004 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) 01005 { 01006 _dbus_warn ("Not expecting error when killing executable: %s: %s\n", 01007 error.name, error.message); 01008 dbus_error_free (&error); 01009 return FALSE; 01010 } 01011 01012 dbus_error_free (&error); 01013 01014 return TRUE; 01015 } 01016 01017 dbus_bool_t 01018 _dbus_spawn_test (const char *test_data_dir) 01019 { 01020 if (!_dbus_test_oom_handling ("spawn_nonexistent", 01021 check_spawn_nonexistent, 01022 NULL)) 01023 return FALSE; 01024 01025 /* Don't run the obnoxious segfault test by default, 01026 * it's a pain to have to click all those error boxes. 01027 */ 01028 if (getenv ("DO_SEGFAULT_TEST")) 01029 if (!_dbus_test_oom_handling ("spawn_segfault", 01030 check_spawn_segfault, 01031 NULL)) 01032 return FALSE; 01033 01034 if (!_dbus_test_oom_handling ("spawn_exit", 01035 check_spawn_exit, 01036 NULL)) 01037 return FALSE; 01038 01039 if (!_dbus_test_oom_handling ("spawn_and_kill", 01040 check_spawn_and_kill, 01041 NULL)) 01042 return FALSE; 01043 01044 return TRUE; 01045 } 01046 #endif
1.7.6.1