5 #if !defined(SPAWN_DEBUG) || defined(_MSC_VER)     8 #define PING() fprintf (stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); fflush (stderr)    37 #include "dbus-spawn.h"    38 #include "dbus-sysdeps.h"    39 #include "dbus-sysdeps-win.h"    40 #include "dbus-internals.h"    41 #include "dbus-test.h"    42 #include "dbus-protocol.h"    44 #define WIN32_LEAN_AND_MEAN    65     HANDLE start_sync_event;
    66 #ifdef DBUS_ENABLE_EMBEDDED_TESTS    68     HANDLE end_sync_event;
    72     DBusSpawnChildSetupFunc child_setup;
    85     DBusBabysitterFinishedFunc finished_cb;
   100 #ifdef DBUS_ENABLE_VERBOSE_MODE   101   static int enabled = -1;
   103   _dbus_trace_ref (
"DBusBabysitter", sitter, old_refcount, new_refcount, why,
   104       "DBUS_BABYSITTER_TRACE", &enabled);
   109 _dbus_babysitter_new (
void)
   112   dbus_int32_t old_refcount;
   120   _dbus_babysitter_trace_ref (sitter, old_refcount, old_refcount+1, __FUNCTION__);
   123   if (sitter->start_sync_event == 
NULL)
   129 #ifdef DBUS_ENABLE_EMBEDDED_TESTS   131   if (sitter->end_sync_event == 
NULL)
   138   sitter->child_handle = 
NULL;
   153   sitter->have_spawn_errno = 
FALSE;
   154   sitter->have_child_status = 
FALSE;
   168   dbus_int32_t old_refcount;
   174   _dbus_babysitter_trace_ref (sitter, old_refcount, old_refcount+1, __FUNCTION__);
   182   _dbus_verbose (
"Closing babysitter\n");
   209   dbus_int32_t old_refcount;
   216   _dbus_babysitter_trace_ref (sitter, old_refcount, old_refcount-1, __FUNCTION__);
   218   if (old_refcount == 1)
   220       close_socket_to_babysitter (sitter);
   222       if (sitter->socket_to_main.sock != INVALID_SOCKET)
   225           sitter->socket_to_main.sock = INVALID_SOCKET;
   229       if (sitter->argv != 
NULL)
   231           for (i = 0; i < sitter->argc; i++)
   232             if (sitter->argv[i] != 
NULL)
   235                 sitter->argv[i] = 
NULL;
   241       if (sitter->envp != 
NULL)
   243           char **e = sitter->envp;
   251       if (sitter->child_handle != 
NULL)
   253           CloseHandle (sitter->child_handle);
   254           sitter->child_handle = 
NULL;
   267       if (sitter->start_sync_event != 
NULL)
   270           CloseHandle (sitter->start_sync_event);
   271           sitter->start_sync_event = 
NULL;
   274 #ifdef DBUS_ENABLE_EMBEDDED_TESTS   275       if (sitter->end_sync_event != 
NULL)
   277           CloseHandle (sitter->end_sync_event);
   278           sitter->end_sync_event = 
NULL;
   292   if (sitter->child_handle == 
NULL)
   296   TerminateProcess (sitter->child_handle, 12345);
   308   return (sitter->child_handle == 
NULL);
   330   if (!sitter->have_child_status ||
   331       sitter->child_status == STILL_ACTIVE)
   334   *status = sitter->child_status;
   356   if (sitter->have_spawn_errno)
   358       char *emsg = _dbus_win_error_string (sitter->spawn_errno);
   360                       "Failed to execute program %s: %s",
   362       _dbus_win_free_error_string (emsg);
   364   else if (sitter->have_child_status)
   368                       "Process %s exited with status %d",
   369                       sitter->
log_name, sitter->child_status);
   375                       "Process %s exited, status unknown",
   400               unsigned int     condition,
   416   close_socket_to_babysitter (sitter);
   420       sitter->finished_cb != 
NULL)
   422       sitter->finished_cb (sitter, sitter->finished_data);
   423       sitter->finished_cb = 
NULL;
   431 protect_argv (
char  **argv,
   439   *new_argv = 
dbus_malloc ((argc + 1) * 
sizeof (
char *));
   440   if (*new_argv == 
NULL)
   443   for (i = 0; i < argc; i++)
   444     (*new_argv)[i] = 
NULL;
   457   for (i = 0; i < argc; i++)
   462       int need_dblquotes = 
FALSE;
   465           if (*p == 
' ' || *p == 
'\t')
   466             need_dblquotes = 
TRUE;
   472               while (*pp && *pp == 
'\\')
   481       q = (*new_argv)[i] = 
dbus_malloc (len + need_dblquotes*2 + 1);
   499               while (*pp && *pp == 
'\\')
   513   (*new_argv)[argc] = 
NULL;
   521 compose_string (
char **strings, 
char separator)
   528   if (!strings || !strings[0])
   530   for (i = 0; strings[i]; i++)
   531     n += strlen (strings[i]) + 1;
   534   buf = p = malloc (n);
   537   for (i = 0; strings[i]; i++)
   539       strcpy (p, strings[i]);
   540       p += strlen (strings[i]);
   551 build_commandline (
char **argv)
   553   return compose_string (argv, 
' ');
   557 build_env_string (
char** envp)
   559   return compose_string (envp, 
'\0');
   563 spawn_program (
char* name, 
char** argv, 
char** envp)
   565   PROCESS_INFORMATION pi = { 
NULL, 0, 0, 0 };
   567   char *arg_string, *env_string;
   572     arg_string = build_commandline (argv + 1);
   576   arg_string = build_commandline (argv);
   579     return INVALID_HANDLE_VALUE;
   581   env_string = build_env_string(envp);
   583   memset (&si, 0, 
sizeof (si));
   586   result = CreateProcessA (name, arg_string, 
NULL, 
NULL, 
FALSE, 0,
   590                            (LPVOID)env_string, 
NULL, &si, &pi);
   596     return INVALID_HANDLE_VALUE;
   598   CloseHandle (pi.hThread);
   603 static DWORD __stdcall
   604 babysitter (
void *parameter)
   611   if (sitter->child_setup)
   614       (*sitter->child_setup) (sitter->user_data);
   617   _dbus_verbose (
"babysitter: spawning %s\n", sitter->
log_name);
   620   handle = spawn_program (sitter->
log_name, sitter->argv, sitter->envp);
   623   if (handle != INVALID_HANDLE_VALUE)
   625       sitter->child_handle = handle;
   629       sitter->child_handle = 
NULL;
   630       sitter->have_spawn_errno = 
TRUE;
   631       sitter->spawn_errno = GetLastError();
   635   SetEvent (sitter->start_sync_event);
   637   if (sitter->child_handle != 
NULL)
   643       WaitForSingleObject (sitter->child_handle, INFINITE);
   646       ret = GetExitCodeProcess (sitter->child_handle, &status);
   649           sitter->child_status = 
status;
   650           sitter->have_child_status = 
TRUE;
   653       CloseHandle (sitter->child_handle);
   654       sitter->child_handle = 
NULL;
   657 #ifdef DBUS_ENABLE_EMBEDDED_TESTS   658   SetEvent (sitter->end_sync_event);
   662   send (sitter->socket_to_main.sock, 
" ", 1, 0);
   674                                    DBusSpawnChildSetupFunc    child_setup,
   679   HANDLE sitter_thread;
   680   DWORD sitter_thread_id;
   682   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   685   if (sitter_p != 
NULL)
   689   sitter = _dbus_babysitter_new ();
   692       _DBUS_SET_OOM (error);
   696   sitter->child_setup = child_setup;
   697   sitter->user_data = user_data;
   702       _DBUS_SET_OOM (error);
   711       _DBUS_SET_OOM (error);
   717                          &sitter->socket_to_main,
   727       _DBUS_SET_OOM (error);
   740       _DBUS_SET_OOM (error);
   744   sitter->argc = protect_argv (argv, &sitter->argv);
   745   if (sitter->argc == -1)
   747       _DBUS_SET_OOM (error);
   753   sitter_thread = (HANDLE) CreateThread (
NULL, 0, babysitter,
   756   if (sitter_thread == 0)
   760                             "Failed to create new thread");
   763   CloseHandle (sitter_thread);
   766   WaitForSingleObject (sitter->start_sync_event, INFINITE);
   769   if (sitter_p != 
NULL)
   774   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   787                                        DBusBabysitterFinishedFunc  finished,
   790   sitter->finished_cb = finished;
   791   sitter->finished_data = user_data;
   794 #ifdef DBUS_ENABLE_EMBEDDED_TESTS   797 get_test_exec (
const char *exe,
   800   const char *dbus_test_exec;
   804   if (dbus_test_exec == 
NULL)
   805     dbus_test_exec = DBUS_TEST_EXEC;
   811                                    dbus_test_exec, exe, DBUS_EXEEXT))
   817   return _dbus_string_get_data (scratch_space);
   820 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)   825   if (sitter->child_handle == 
NULL)
   828   WaitForSingleObject (sitter->end_sync_event, INFINITE);
   832 check_spawn_nonexistent (
void *data)
   844   argv[0] = 
"/this/does/not/exist/32542sdgafgafdg";
   849       _dbus_babysitter_block_for_child_exit (sitter);
   858       _dbus_warn (
"Did not get an error launching nonexistent executable\n");
   865       _dbus_warn (
"Not expecting error when launching nonexistent executable: %s: %s\n",
   877 check_spawn_segfault (
void *data)
   890   argv[0] = get_test_exec (
"test-segfault", &argv0);
   902       _dbus_babysitter_block_for_child_exit (sitter);
   913       _dbus_warn (
"Did not get an error launching segfaulting binary\n");
   920       _dbus_warn (
"Not expecting error when launching segfaulting executable: %s: %s\n",
   932 check_spawn_exit (
void *data)
   945   argv[0] = get_test_exec (
"test-exit", &argv0);
   957       _dbus_babysitter_block_for_child_exit (sitter);
   968       _dbus_warn (
"Did not get an error launching binary that exited with failure code\n");
   975       _dbus_warn (
"Not expecting error when launching exiting executable: %s: %s\n",
   987 check_spawn_and_kill (
void *data)
  1000   argv[0] = get_test_exec (
"test-sleep-forever", &argv0);
  1002   if (argv[0] == NULL)
  1014       _dbus_babysitter_block_for_child_exit (sitter);
  1026       _dbus_warn (
"Did not get an error after killing spawned binary\n");
  1033       _dbus_warn (
"Not expecting error when killing executable: %s: %s\n",
  1045 _dbus_spawn_test (
const char *test_data_dir)
  1047   if (!_dbus_test_oom_handling (
"spawn_nonexistent",
  1048                                 check_spawn_nonexistent,
  1055   if (getenv (
"DO_SEGFAULT_TEST"))
  1056     if (!_dbus_test_oom_handling (
"spawn_segfault",
  1057                                   check_spawn_segfault,
  1061   if (!_dbus_test_oom_handling (
"spawn_exit",
  1066   if (!_dbus_test_oom_handling (
"spawn_and_kill",
  1067                                 check_spawn_and_kill,
 dbus_bool_t dbus_error_has_name(const DBusError *error, const char *name)
Checks whether the error is set and has the given name. 
An atomic integer safe to increment or decrement from multiple threads. 
const char * message
public error message field 
DBusWatch * _dbus_watch_new(DBusPollable fd, unsigned int flags, dbus_bool_t enabled, DBusWatchHandler handler, void *data, DBusFreeFunction free_data_function)
Creates a new DBusWatch. 
Implementation of DBusWatch. 
#define NULL
A null pointer, defined appropriately for C or C++. 
#define DBUS_ERROR_SPAWN_EXEC_FAILED
While starting a new process, the exec() call failed. 
void(* DBusFreeFunction)(void *memory)
The type of a function which frees a block of memory. 
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0(). 
dbus_bool_t _dbus_socketpair(DBusSocket *fd1, DBusSocket *fd2, dbus_bool_t blocking, DBusError *error)
Creates pair of connect sockets (as in socketpair()). 
void(* DBusWatchToggledFunction)(DBusWatch *watch, void *data)
Called when dbus_watch_get_enabled() may return a different value than it did before. 
#define DBUS_ERROR_SPAWN_CHILD_EXITED
While starting a new process, the child exited with a status code. 
int status
Exit status code. 
#define _dbus_assert(condition)
Aborts with an error message if the condition is false. 
void dbus_error_free(DBusError *error)
Frees an error that's been set (or just initialized), then reinitializes the error as in dbus_error_i...
void _dbus_watch_list_free(DBusWatchList *watch_list)
Frees a DBusWatchList. 
DBusWatchList * _dbus_watch_list_new(void)
Creates a new watch list. 
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string. 
dbus_bool_t _dbus_close_socket(DBusSocket fd, DBusError *error)
Closes a socket. 
dbus_bool_t _dbus_babysitter_get_child_exited(DBusBabysitter *sitter)
Checks whether the child has exited, without blocking. 
dbus_bool_t _dbus_watch_list_set_functions(DBusWatchList *watch_list, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function)
Sets the watch functions. 
DBusWatchList * watches
Watches. 
void * dbus_malloc(size_t bytes)
Allocates the given number of bytes, as with standard malloc(). 
#define dbus_new0(type, count)
Safe macro for using dbus_malloc0(). 
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE. 
DBusWatch * sitter_watch
Sitter pipe watch. 
dbus_bool_t _dbus_babysitter_get_child_exit_status(DBusBabysitter *sitter, int *status)
Gets the exit status of the child. 
void _dbus_babysitter_kill_child(DBusBabysitter *sitter)
Blocks until the babysitter process gives us the PID of the spawned grandchild, then kills the spawne...
Babysitter implementation details. 
dbus_bool_t _dbus_spawn_async_with_babysitter(DBusBabysitter **sitter_p, const char *log_name, char **argv, char **env, DBusSpawnChildSetupFunc child_setup, void *user_data, DBusError *error)
Spawns a new process. 
void _dbus_warn(const char *format,...)
Prints a warning message to stderr. 
dbus_int32_t _dbus_atomic_inc(DBusAtomic *atomic)
Atomically increments an integer. 
dbus_bool_t _dbus_string_append_printf(DBusString *str, const char *format,...)
Appends a printf-style formatted string to the DBusString. 
void _dbus_watch_invalidate(DBusWatch *watch)
Clears the file descriptor from a now-invalid watch object so that no one tries to use it...
dbus_bool_t _dbus_babysitter_set_watch_functions(DBusBabysitter *sitter, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function)
Sets watch functions to notify us when the babysitter object needs to read/write file descriptors...
Object representing an exception. 
void dbus_set_error(DBusError *error, const char *name, const char *format,...)
Assigns an error name and message to a DBusError. 
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init(). 
#define TRUE
Expands to "1". 
#define _dbus_assert_not_reached(explanation)
Aborts with an error message if called. 
#define DBUS_ERROR_FAILED
A generic error; "something went wrong" - see the error message for more. 
dbus_bool_t _dbus_watch_list_add_watch(DBusWatchList *watch_list, DBusWatch *watch)
Adds a new watch to the watch list, invoking the application DBusAddWatchFunction if appropriate...
const char * name
public error name field 
dbus_bool_t(* DBusAddWatchFunction)(DBusWatch *watch, void *data)
Called when libdbus needs a new watch to be monitored by the main loop. 
void(* DBusRemoveWatchFunction)(DBusWatch *watch, void *data)
Called when libdbus no longer needs a watch to be monitored by the main loop. 
DBusWatchList implementation details. 
void _dbus_watch_list_remove_watch(DBusWatchList *watch_list, DBusWatch *watch)
Removes a watch from the watch list, invoking the application's DBusRemoveWatchFunction if appropriat...
void _dbus_babysitter_unref(DBusBabysitter *sitter)
Decrement the reference count on the babysitter object. 
void dbus_error_init(DBusError *error)
Initializes a DBusError structure. 
dbus_int32_t _dbus_atomic_dec(DBusAtomic *atomic)
Atomically decrement an integer. 
#define DBUS_ERROR_SPAWN_FORK_FAILED
While starting a new process, the fork() call failed. 
char * log_name
the name under which to log messages about this process being spawned 
void _dbus_watch_unref(DBusWatch *watch)
Decrements the reference count of a DBusWatch object and finalizes the object if the count reaches ze...
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation. 
#define FALSE
Expands to "0". 
void dbus_set_error_const(DBusError *error, const char *name, const char *message)
Assigns an error name and message to a DBusError. 
DBusSocket socket_to_babysitter
Connection to the babysitter process. 
char * _dbus_strdup(const char *str)
Duplicates a string. 
void _dbus_babysitter_set_child_exit_error(DBusBabysitter *sitter, DBusError *error)
Sets the DBusError with an explanation of why the spawned child process exited (on a signal...
const char * _dbus_getenv(const char *varname)
Wrapper for getenv(). 
dbus_bool_t dbus_error_is_set(const DBusError *error)
Checks whether an error occurred (the error is set). 
DBusBabysitter * _dbus_babysitter_ref(DBusBabysitter *sitter)
Increment the reference count on the babysitter object.