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;
 
   80     DBusBabysitterFinishedFunc finished_cb;
 
   95 #ifdef DBUS_ENABLE_VERBOSE_MODE 
   96   static int enabled = -1;
 
   98   _dbus_trace_ref (
"DBusBabysitter", sitter, old_refcount, new_refcount, why,
 
   99       "DBUS_BABYSITTER_TRACE", &enabled);
 
  104 _dbus_babysitter_new (
void)
 
  115   _dbus_babysitter_trace_ref (sitter, old_refcount, old_refcount+1, __FUNCTION__);
 
  118   if (sitter->start_sync_event == 
NULL)
 
  124   sitter->child_handle = 
NULL;
 
  139   sitter->have_spawn_errno = 
FALSE;
 
  140   sitter->have_child_status = 
FALSE;
 
  160   _dbus_babysitter_trace_ref (sitter, old_refcount, old_refcount+1, __FUNCTION__);
 
  168   _dbus_verbose (
"Closing babysitter\n");
 
  202   _dbus_babysitter_trace_ref (sitter, old_refcount, old_refcount-1, __FUNCTION__);
 
  204   if (old_refcount == 1)
 
  206       close_socket_to_babysitter (sitter);
 
  208       if (sitter->socket_to_main.sock != INVALID_SOCKET)
 
  211           sitter->socket_to_main.sock = INVALID_SOCKET;
 
  215       if (sitter->argv != 
NULL)
 
  217           for (i = 0; i < sitter->argc; i++)
 
  218             if (sitter->argv[i] != 
NULL)
 
  221                 sitter->argv[i] = 
NULL;
 
  227       if (sitter->envp != 
NULL)
 
  229           char **e = sitter->envp;
 
  237       if (sitter->child_handle != 
NULL)
 
  239           CloseHandle (sitter->child_handle);
 
  240           sitter->child_handle = 
NULL;
 
  253       if (sitter->start_sync_event != 
NULL)
 
  256           CloseHandle (sitter->start_sync_event);
 
  257           sitter->start_sync_event = 
NULL;
 
  260       if (sitter->thread_handle)
 
  262           CloseHandle (sitter->thread_handle);
 
  263           sitter->thread_handle = 
NULL;
 
  276   if (sitter->child_handle == 
NULL)
 
  280   TerminateProcess (sitter->child_handle, 12345);
 
  292   return (sitter->child_handle == 
NULL);
 
  314   if (!sitter->have_child_status ||
 
  315       sitter->child_status == STILL_ACTIVE)
 
  318   *status = sitter->child_status;
 
  340   if (sitter->have_spawn_errno)
 
  342       char *emsg = _dbus_win_error_string (sitter->spawn_errno);
 
  344                       "Failed to execute program %s: %s",
 
  346       _dbus_win_free_error_string (emsg);
 
  348   else if (sitter->have_child_status)
 
  352                       "Process %s exited with status %d",
 
  353                       sitter->
log_name, sitter->child_status);
 
  359                       "Process %s exited, status unknown",
 
  384               unsigned int     condition,
 
  400   close_socket_to_babysitter (sitter);
 
  404       sitter->finished_cb != 
NULL)
 
  406       sitter->finished_cb (sitter, sitter->finished_data);
 
  407       sitter->finished_cb = 
NULL;
 
  415 protect_argv (
char  * 
const *argv,
 
  423   *new_argv = 
dbus_malloc ((argc + 1) * 
sizeof (
char *));
 
  424   if (*new_argv == 
NULL)
 
  427   for (i = 0; i < argc; i++)
 
  428     (*new_argv)[i] = 
NULL;
 
  441   for (i = 0; i < argc; i++)
 
  443       const char *p = argv[i];
 
  446       int need_dblquotes = 
FALSE;
 
  449           if (*p == 
' ' || *p == 
'\t')
 
  450             need_dblquotes = 
TRUE;
 
  456               while (*pp && *pp == 
'\\')
 
  465       q = (*new_argv)[i] = 
dbus_malloc (len + need_dblquotes*2 + 1);
 
  483               while (*pp && *pp == 
'\\')
 
  497   (*new_argv)[argc] = 
NULL;
 
  505 compose_string (
char **strings, 
char separator)
 
  512   if (!strings || !strings[0])
 
  514   for (i = 0; strings[i]; i++)
 
  515     n += strlen (strings[i]) + 1;
 
  518   buf = p = malloc (n);
 
  521   for (i = 0; strings[i]; i++)
 
  523       strcpy (p, strings[i]);
 
  524       p += strlen (strings[i]);
 
  535 build_commandline (
char **argv)
 
  537   return compose_string (argv, 
' ');
 
  541 build_env_string (
char** envp)
 
  543   return compose_string (envp, 
'\0');
 
  547 spawn_program (
char* name, 
char** argv, 
char** envp)
 
  549   PROCESS_INFORMATION pi = { 
NULL, 0, 0, 0 };
 
  551   char *arg_string, *env_string;
 
  556     arg_string = build_commandline (argv + 1);
 
  560   arg_string = build_commandline (argv);
 
  563     return INVALID_HANDLE_VALUE;
 
  565   env_string = build_env_string(envp);
 
  567   memset (&si, 0, 
sizeof (si));
 
  570   result = CreateProcessA (name, arg_string, 
NULL, 
NULL, 
FALSE, 0,
 
  574                            (LPVOID)env_string, 
NULL, &si, &pi);
 
  580     return INVALID_HANDLE_VALUE;
 
  582   CloseHandle (pi.hThread);
 
  587 static DWORD __stdcall
 
  588 babysitter (
void *parameter)
 
  595   _dbus_verbose (
"babysitter: spawning %s\n", sitter->
log_name);
 
  598   handle = spawn_program (sitter->
log_name, sitter->argv, sitter->envp);
 
  601   if (handle != INVALID_HANDLE_VALUE)
 
  603       sitter->child_handle = handle;
 
  607       sitter->child_handle = 
NULL;
 
  608       sitter->have_spawn_errno = 
TRUE;
 
  609       sitter->spawn_errno = GetLastError();
 
  613   SetEvent (sitter->start_sync_event);
 
  615   if (sitter->child_handle != 
NULL)
 
  621       WaitForSingleObject (sitter->child_handle, INFINITE);
 
  624       ret = GetExitCodeProcess (sitter->child_handle, &status);
 
  627           sitter->child_status = status;
 
  628           sitter->have_child_status = 
TRUE;
 
  631       CloseHandle (sitter->child_handle);
 
  632       sitter->child_handle = 
NULL;
 
  636   send (sitter->socket_to_main.sock, 
" ", 1, 0);
 
  645                                    const char                *log_name,
 
  648                                    DBusSpawnFlags             flags _DBUS_GNUC_UNUSED,
 
  649                                    DBusSpawnChildSetupFunc    child_setup _DBUS_GNUC_UNUSED,
 
  650                                    void                      *user_data _DBUS_GNUC_UNUSED,
 
  654   DWORD sitter_thread_id;
 
  656   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
  659   if (sitter_p != 
NULL)
 
  663   sitter = _dbus_babysitter_new ();
 
  666       _DBUS_SET_OOM (error);
 
  673       _DBUS_SET_OOM (error);
 
  682       _DBUS_SET_OOM (error);
 
  688                          &sitter->socket_to_main,
 
  698       _DBUS_SET_OOM (error);
 
  711       _DBUS_SET_OOM (error);
 
  715   sitter->argc = protect_argv (argv, &sitter->argv);
 
  716   if (sitter->argc == -1)
 
  718       _DBUS_SET_OOM (error);
 
  724   sitter->thread_handle = (HANDLE) CreateThread (
NULL, 0, babysitter,
 
  727   if (sitter->thread_handle == 
NULL)
 
  731                             "Failed to create new thread");
 
  736   WaitForSingleObject (sitter->start_sync_event, INFINITE);
 
  739   if (sitter_p != 
NULL)
 
  744   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
  757                                        DBusBabysitterFinishedFunc  finished,
 
  760   sitter->finished_cb = finished;
 
  761   sitter->finished_data = user_data;
 
  764 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL) 
  772   WaitForSingleObject (sitter->thread_handle, INFINITE);
 
  
DBusBabysitter * _dbus_babysitter_ref(DBusBabysitter *sitter)
Increment the reference count on the babysitter object.
dbus_int32_t _dbus_atomic_dec(DBusAtomic *atomic)
Atomically decrement an integer.
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.
DBusWatchList * _dbus_watch_list_new(void)
Creates a new watch list.
dbus_bool_t _dbus_babysitter_get_child_exited(DBusBabysitter *sitter)
Checks whether the child has exited, without blocking.
void dbus_set_error_const(DBusError *error, const char *name, const char *message)
Assigns an error name and message to a DBusError.
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_set_child_exit_error(DBusBabysitter *sitter, DBusError *error)
Sets the DBusError with an explanation of why the spawned child process exited (on a signal,...
void(* DBusFreeFunction)(void *memory)
char * log_name
the name under which to log messages about this process being spawned
Implementation of DBusWatch.
dbus_bool_t _dbus_spawn_async_with_babysitter(DBusBabysitter **sitter_p, const char *log_name, char *const *argv, char **env, DBusSpawnFlags flags, DBusSpawnChildSetupFunc child_setup, void *user_data, DBusError *error)
Spawns a new process.
#define DBUS_ERROR_SPAWN_CHILD_EXITED
While starting a new process, the child exited with a status code.
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.
@ DBUS_WATCH_READABLE
As in POLLIN.
#define DBUS_ERROR_FAILED
A generic error; "something went wrong" - see the error message for more.
#define DBUS_ERROR_SPAWN_EXEC_FAILED
While starting a new process, the exec() call failed.
dbus_bool_t(* DBusAddWatchFunction)(DBusWatch *watch, void *data)
Called when libdbus needs a new watch to be monitored by the main loop.
void _dbus_watch_unref(DBusWatch *watch)
Decrements the reference count of a DBusWatch object and finalizes the object if the count reaches ze...
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
void * dbus_malloc(size_t bytes)
Allocates the given number of bytes, as with standard malloc().
Babysitter implementation details.
#define _dbus_assert_not_reached(explanation)
DBusWatchList * watches
Watches.
DBusWatchList implementation details.
#define DBUS_ERROR_SPAWN_FORK_FAILED
While starting a new process, the fork() call failed.
An atomic integer safe to increment or decrement from multiple threads.
dbus_bool_t _dbus_close_socket(DBusSocket fd, DBusError *error)
Closes a socket.
void(* DBusWatchToggledFunction)(DBusWatch *watch, void *data)
Called when dbus_watch_get_enabled() may return a different value than it did before.
#define _dbus_assert(condition)
void _dbus_babysitter_unref(DBusBabysitter *sitter)
Decrement the reference count on the babysitter object.
dbus_bool_t _dbus_socketpair(DBusSocket *fd1, DBusSocket *fd2, dbus_bool_t blocking, DBusError *error)
Creates pair of connect sockets (as in socketpair()).
char * _dbus_strdup(const char *str)
Duplicates a string.
void _dbus_watch_list_free(DBusWatchList *watch_list)
Frees a DBusWatchList.
Object representing an exception.
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_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.
DBusSocket socket_to_babysitter
Connection to the babysitter process.
void dbus_set_error(DBusError *error, const char *name, const char *format,...)
Assigns an error name and message to a DBusError.
DBusWatch * sitter_watch
Sitter pipe watch.
void(* DBusRemoveWatchFunction)(DBusWatch *watch, void *data)
Called when libdbus no longer needs a watch to be monitored by the main loop.
dbus_int32_t _dbus_atomic_inc(DBusAtomic *atomic)
Atomically increments an integer.
void _dbus_babysitter_kill_child(DBusBabysitter *sitter)
Blocks until the babysitter process gives us the PID of the spawned grandchild, then kills the spawne...
#define dbus_new0(type, count)
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.
dbus_bool_t _dbus_babysitter_get_child_exit_status(DBusBabysitter *sitter, int *status)
Gets the exit status of the child.
dbus_uint32_t dbus_bool_t