5#if !defined(SPAWN_DEBUG) || defined(_MSC_VER)
8#define PING() fprintf (stderr, "%s:%s:%d\n", __FILE__, _DBUS_FUNCTION_NAME, __LINE__); fflush (stderr)
39#include "dbus-spawn.h"
40#include "dbus-sysdeps.h"
41#include "dbus-sysdeps-win.h"
42#include "dbus-internals.h"
44#include "dbus-protocol.h"
46#define WIN32_LEAN_AND_MEAN
75 DBusBabysitterFinishedFunc finished_cb;
78 dbus_bool_t have_spawn_errno;
90#ifdef DBUS_ENABLE_VERBOSE_MODE
91 static int enabled = -1;
93 _dbus_trace_ref (
"DBusBabysitter", sitter, old_refcount, new_refcount, why,
94 "DBUS_BABYSITTER_TRACE", &enabled);
99_dbus_babysitter_new (
void)
102 dbus_int32_t old_refcount;
110 _dbus_babysitter_trace_ref (sitter, old_refcount, old_refcount+1, _DBUS_FUNCTION_NAME);
112 sitter->child_handle =
NULL;
123 sitter->have_spawn_errno =
FALSE;
138 dbus_int32_t old_refcount;
144 _dbus_babysitter_trace_ref (sitter, old_refcount, old_refcount+1, _DBUS_FUNCTION_NAME);
152 _dbus_verbose (
"Closing babysitter\n");
178 dbus_int32_t old_refcount;
185 _dbus_babysitter_trace_ref (sitter, old_refcount, old_refcount-1, _DBUS_FUNCTION_NAME);
187 if (old_refcount == 1)
189 close_socket_to_babysitter (sitter);
191 if (sitter->socket_to_main.sock != INVALID_SOCKET)
194 sitter->socket_to_main.sock = INVALID_SOCKET;
197 if (sitter->child_handle !=
NULL)
199 CloseHandle (sitter->child_handle);
200 sitter->child_handle =
NULL;
213 if (sitter->thread_handle)
215 CloseHandle (sitter->thread_handle);
216 sitter->thread_handle =
NULL;
229 if (sitter->child_handle ==
NULL)
233 TerminateProcess (sitter->child_handle, 12345);
245 return (sitter->child_handle ==
NULL);
268 sitter->child_status == STILL_ACTIVE)
271 *status = sitter->child_status;
293 if (sitter->have_spawn_errno)
295 char *emsg = _dbus_win_error_string (sitter->spawn_errno);
297 "Failed to execute program %s: %s",
299 _dbus_win_free_error_string (emsg);
305 "Process %s exited with status %d",
306 sitter->
log_name, sitter->child_status);
312 "Process %s exited, status unknown",
337 unsigned int condition,
353 close_socket_to_babysitter (sitter);
357 sitter->finished_cb !=
NULL)
359 sitter->finished_cb (sitter, sitter->finished_data);
360 sitter->finished_cb =
NULL;
368protect_argv (
char *
const *argv,
381 for (i = 0; i < argc; i++)
395 for (i = 0; i < argc; i++)
397 const char *p = argv[i];
400 int need_dblquotes =
FALSE;
403 if (*p ==
' ' || *p ==
'\t')
404 need_dblquotes =
TRUE;
410 while (*pp && *pp ==
'\\')
419 q = args[i] =
dbus_malloc (len + need_dblquotes*2 + 1);
439 while (*pp && *pp ==
'\\')
460build_commandline (
char **argv,
DBusString *result)
466build_env_block (
char** envp,
DBusString *result)
492_dbus_spawn_program (
const char *name,
495 dbus_bool_t inherit_handles,
498 PROCESS_INFORMATION pi = {
NULL, 0, 0, 0 };
500 DBusString arg_string = _DBUS_STRING_INIT_INVALID;
501 DBusString env_block = _DBUS_STRING_INIT_INVALID;
507 _DBUS_SET_OOM (error);
514 if (!build_commandline (argv + 1, &arg_string))
515 _DBUS_SET_OOM (error);
519 if (!build_commandline (argv, &arg_string))
521 _DBUS_SET_OOM (error);
525 if (_dbus_string_get_length (&arg_string) == 0)
533 if (!build_env_block (envp, &env_block))
535 _DBUS_SET_OOM (error);
539 env = _dbus_string_get_data (&env_block);
542 memset (&si, 0,
sizeof (si));
545#ifdef DBUS_ENABLE_VERBOSE_MODE
551 _DBUS_SET_OOM (error);
558 _DBUS_SET_OOM (error);
562 _dbus_verbose (
"spawning '%s'' with args: '%s' env: '%s'\n", name,
563 _dbus_string_get_const_data (&arg_string),
564 _dbus_string_get_const_data (&temp));
570 result = CreateProcessA (name, _dbus_string_get_const_data (&arg_string),
NULL,
NULL,
FALSE, 0,
572 result = CreateProcessA (
NULL,
573 _dbus_string_get_data (&arg_string),
579 env,
NULL, &si, &pi);
582 _dbus_win_set_error_from_last_error (error,
"Unable to start '%s' with arguments '%s'",
583 name, _dbus_string_get_const_data (&arg_string));
588 _DBUS_ASSERT_ERROR_XOR_BOOL (error, result);
595 CloseHandle (pi.hThread);
603static DWORD __stdcall
604babysitter (
void *parameter)
610 if (sitter->child_handle !=
NULL)
616 WaitForSingleObject (sitter->child_handle, INFINITE);
619 ret = GetExitCodeProcess (sitter->child_handle, &status);
622 sitter->child_status = status;
626 CloseHandle (sitter->child_handle);
627 sitter->child_handle =
NULL;
631 send (sitter->socket_to_main.sock,
" ", 1, 0);
640 const char *log_name,
643 DBusSpawnFlags flags _DBUS_GNUC_UNUSED,
644 DBusSpawnChildSetupFunc child_setup _DBUS_GNUC_UNUSED,
645 void *user_data _DBUS_GNUC_UNUSED,
649 DWORD sitter_thread_id;
652 char **my_argv =
NULL;
655 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
658 if (sitter_p !=
NULL)
662 sitter = _dbus_babysitter_new ();
665 _DBUS_SET_OOM (error);
672 _DBUS_SET_OOM (error);
681 _DBUS_SET_OOM (error);
687 &sitter->socket_to_main,
697 _DBUS_SET_OOM (error);
710 _DBUS_SET_OOM (error);
714 argc = protect_argv (argv, &my_argv);
717 _DBUS_SET_OOM (error);
721 _dbus_verbose (
"babysitter: spawn child '%s'\n", my_argv[0]);
724 handle = _dbus_spawn_program (sitter->
log_name, my_argv, (
char **) envp,
FALSE, &local_error);
736 sitter->child_handle =
NULL;
737 sitter->have_spawn_errno =
TRUE;
738 sitter->spawn_errno = ERROR_NOT_ENOUGH_MEMORY;
743 sitter->child_handle =
NULL;
744 sitter->have_spawn_errno =
TRUE;
745 sitter->spawn_errno = GetLastError();
747 "Failed to spawn child: %s", local_error.
message);
755 sitter->child_handle = handle;
758 sitter->thread_handle = (HANDLE) CreateThread (
NULL, 0, babysitter,
761 if (sitter->thread_handle ==
NULL)
765 "Failed to create new thread");
770 if (sitter_p !=
NULL)
775 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
788 DBusBabysitterFinishedFunc finished,
791 sitter->finished_cb = finished;
792 sitter->finished_data = user_data;
795#define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)
803 WaitForSingleObject (sitter->thread_handle, INFINITE);
void(* DBusWatchToggledFunction)(DBusWatch *watch, void *data)
Called when dbus_watch_get_enabled() may return a different value than it did before.
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.
@ DBUS_WATCH_READABLE
As in POLLIN.
#define DBUS_ERROR_INIT
Expands to a suitable initializer for a DBusError on the stack.
void dbus_move_error(DBusError *src, DBusError *dest)
Moves an error src into dest, freeing src and overwriting dest.
void dbus_set_error_const(DBusError *error, const char *name, const char *message)
Assigns an error name and message to a DBusError.
dbus_bool_t dbus_error_has_name(const DBusError *error, const char *name)
Checks whether the error is set and has the given name.
void dbus_set_error(DBusError *error, const char *name, const char *format,...)
Assigns an error name and message to a DBusError.
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...
#define _dbus_assert_not_reached(explanation)
Aborts with an error message if called.
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
dbus_bool_t _dbus_babysitter_get_child_exit_status(DBusBabysitter *sitter, int *status)
Gets the exit status of the child.
void _dbus_babysitter_unref(DBusBabysitter *sitter)
Decrement the reference count on the babysitter object.
dbus_bool_t _dbus_babysitter_get_child_exited(DBusBabysitter *sitter)
Checks whether the child has exited, without blocking.
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.
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,...
void _dbus_babysitter_kill_child(DBusBabysitter *sitter)
Blocks until the babysitter process gives us the PID of the spawned grandchild, then kills the spawne...
DBusBabysitter * _dbus_babysitter_ref(DBusBabysitter *sitter)
Increment the reference count on the babysitter object.
dbus_bool_t _dbus_spawn_async_with_babysitter(DBusBabysitter **sitter_p, const char *log_name, char *const *argv, char *const *env, DBusSpawnFlags flags, DBusSpawnChildSetupFunc child_setup, void *user_data, DBusError *error)
Spawns a new process.
#define NULL
A null pointer, defined appropriately for C or C++.
#define TRUE
Expands to "1".
#define FALSE
Expands to "0".
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().
#define dbus_new0(type, count)
Safe macro for using dbus_malloc0().
void dbus_free_string_array(char **str_array)
Frees a NULL-terminated array of strings.
void * dbus_malloc(size_t bytes)
Allocates the given number of bytes, as with standard malloc().
#define DBUS_ERROR_SPAWN_CHILD_EXITED
While starting a new process, the child exited with a status code.
#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.
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation.
#define DBUS_ERROR_SPAWN_FORK_FAILED
While starting a new process, the fork() call failed.
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
dbus_bool_t _dbus_string_append_strings(DBusString *str, char **strings, char separator)
Append vector with strings connected by separator.
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init(), and fills it with the same contents as _DBUS_STRING_IN...
dbus_bool_t _dbus_string_append_byte(DBusString *str, unsigned char byte)
Appends a single byte to the string, returning FALSE if not enough memory.
dbus_bool_t _dbus_socketpair(DBusSocket *fd1, DBusSocket *fd2, dbus_bool_t blocking, DBusError *error)
Creates pair of connect sockets (as in socketpair()).
dbus_int32_t _dbus_atomic_dec(DBusAtomic *atomic)
Atomically decrement an integer.
dbus_bool_t _dbus_close_socket(DBusSocket *fd, DBusError *error)
Closes a socket and invalidates it.
dbus_int32_t _dbus_atomic_inc(DBusAtomic *atomic)
Atomically increments 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.
void _dbus_watch_list_free(DBusWatchList *watch_list)
Frees a DBusWatchList.
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.
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.
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_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_watch_invalidate(DBusWatch *watch)
Clears the file descriptor from a now-invalid watch object so that no one tries to use it.
An atomic integer safe to increment or decrement from multiple threads.
Babysitter implementation details.
DBusWatch * sitter_watch
Sitter pipe watch.
DBusSocket socket_to_babysitter
Connection to the babysitter process.
unsigned int have_child_status
True if child status has been reaped.
char * log_name
the name under which to log messages about this process being spawned
int refcount
Reference count.
DBusWatchList * watches
Watches.
Object representing an exception.
const char * message
public error message field
DBusWatchList implementation details.
Implementation of DBusWatch.