5
#if !defined(SPAWN_DEBUG) || defined(_MSC_VER)
8
#define PING() fprintf (stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); fflush (stderr)
13
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
14
/* dbus-spawn-win32.c Wrapper around g_spawn
16
* Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
17
* Copyright (C) 2003 CodeFactory AB
18
* Copyright (C) 2005 Novell, Inc.
20
* Licensed under the Academic Free License version 2.1
22
* This program is free software; you can redistribute it and/or modify
23
* it under the terms of the GNU General Public License as published by
24
* the Free Software Foundation; either version 2 of the License, or
25
* (at your option) any later version.
27
* This program is distributed in the hope that it will be useful,
28
* but WITHOUT ANY WARRANTY; without even the implied warranty of
29
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30
* GNU General Public License for more details.
32
* You should have received a copy of the GNU General Public License
33
* along with this program; if not, write to the Free Software
34
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
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
46
//#include <windows.h>
58
* Babysitter implementation details
64
HANDLE start_sync_event;
65
#ifdef DBUS_BUILD_TESTS
67
HANDLE end_sync_event;
71
DBusSpawnChildSetupFunc child_setup;
79
int socket_to_babysitter; /* Connection to the babysitter thread */
82
DBusWatchList *watches;
83
DBusWatch *sitter_watch;
85
dbus_bool_t have_spawn_errno;
87
dbus_bool_t have_child_status;
91
static DBusBabysitter*
92
_dbus_babysitter_new (void)
94
DBusBabysitter *sitter;
96
sitter = dbus_new0 (DBusBabysitter, 1);
100
sitter->refcount = 1;
102
sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
103
if (sitter->start_sync_event == NULL)
105
_dbus_babysitter_unref (sitter);
109
#ifdef DBUS_BUILD_TESTS
110
sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
111
if (sitter->end_sync_event == NULL)
113
_dbus_babysitter_unref (sitter);
118
sitter->child_handle = NULL;
120
sitter->socket_to_babysitter = sitter->socket_to_main = -1;
126
sitter->watches = _dbus_watch_list_new ();
127
if (sitter->watches == NULL)
129
_dbus_babysitter_unref (sitter);
133
sitter->have_spawn_errno = FALSE;
134
sitter->have_child_status = FALSE;
140
* Increment the reference count on the babysitter object.
142
* @param sitter the babysitter
143
* @returns the babysitter
146
_dbus_babysitter_ref (DBusBabysitter *sitter)
149
_dbus_assert (sitter != NULL);
150
_dbus_assert (sitter->refcount > 0);
152
sitter->refcount += 1;
158
* Decrement the reference count on the babysitter object.
160
* @param sitter the babysitter
163
_dbus_babysitter_unref (DBusBabysitter *sitter)
168
_dbus_assert (sitter != NULL);
169
_dbus_assert (sitter->refcount > 0);
171
sitter->refcount -= 1;
173
if (sitter->refcount == 0)
175
if (sitter->socket_to_babysitter != -1)
177
_dbus_close_socket (sitter->socket_to_babysitter, NULL);
178
sitter->socket_to_babysitter = -1;
181
if (sitter->socket_to_main != -1)
183
_dbus_close_socket (sitter->socket_to_main, NULL);
184
sitter->socket_to_main = -1;
188
if (sitter->argv != NULL)
190
for (i = 0; i < sitter->argc; i++)
191
if (sitter->argv[i] != NULL)
193
dbus_free (sitter->argv[i]);
194
sitter->argv[i] = NULL;
196
dbus_free (sitter->argv);
200
if (sitter->envp != NULL)
202
char **e = sitter->envp;
206
dbus_free (sitter->envp);
210
if (sitter->child_handle != NULL)
212
CloseHandle (sitter->child_handle);
213
sitter->child_handle = NULL;
216
if (sitter->sitter_watch)
218
_dbus_watch_invalidate (sitter->sitter_watch);
219
_dbus_watch_unref (sitter->sitter_watch);
220
sitter->sitter_watch = NULL;
224
_dbus_watch_list_free (sitter->watches);
226
if (sitter->start_sync_event != NULL)
229
CloseHandle (sitter->start_sync_event);
230
sitter->start_sync_event = NULL;
233
#ifdef DBUS_BUILD_TESTS
234
if (sitter->end_sync_event != NULL)
236
CloseHandle (sitter->end_sync_event);
237
sitter->end_sync_event = NULL;
241
dbus_free (sitter->executable);
248
_dbus_babysitter_kill_child (DBusBabysitter *sitter)
251
if (sitter->child_handle == NULL)
252
return; /* child is already dead, or we're so hosed we'll never recover */
255
TerminateProcess (sitter->child_handle, 12345);
259
* Checks whether the child has exited, without blocking.
261
* @param sitter the babysitter
264
_dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
267
return (sitter->child_handle == NULL);
271
* Gets the exit status of the child. We do this so implementation specific
272
* detail is not cluttering up dbus, for example the system launcher code.
273
* This can only be called if the child has exited, i.e. call
274
* _dbus_babysitter_get_child_exited(). It returns FALSE if the child
275
* did not return a status code, e.g. because the child was signaled
276
* or we failed to ever launch the child in the first place.
278
* @param sitter the babysitter
279
* @param status the returned status code
280
* @returns #FALSE on failure
283
_dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter,
286
if (!_dbus_babysitter_get_child_exited (sitter))
287
_dbus_assert_not_reached ("Child has not exited");
289
if (!sitter->have_child_status ||
290
sitter->child_status == STILL_ACTIVE)
293
*status = sitter->child_status;
298
* Sets the #DBusError with an explanation of why the spawned
299
* child process exited (on a signal, or whatever). If
300
* the child process has not exited, does nothing (error
301
* will remain unset).
303
* @param sitter the babysitter
304
* @param error an error to fill in
307
_dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
311
if (!_dbus_babysitter_get_child_exited (sitter))
315
if (sitter->have_spawn_errno)
317
char *emsg = _dbus_win_error_string (sitter->spawn_errno);
318
dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
319
"Failed to execute program %s: %s",
320
sitter->executable, emsg);
321
_dbus_win_free_error_string (emsg);
323
else if (sitter->have_child_status)
326
dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
327
"Process %s exited with status %d",
328
sitter->executable, sitter->child_status);
333
dbus_set_error (error, DBUS_ERROR_FAILED,
334
"Process %s exited, status unknown",
341
_dbus_babysitter_set_watch_functions (DBusBabysitter *sitter,
342
DBusAddWatchFunction add_function,
343
DBusRemoveWatchFunction remove_function,
344
DBusWatchToggledFunction toggled_function,
346
DBusFreeFunction free_data_function)
349
return _dbus_watch_list_set_functions (sitter->watches,
358
handle_watch (DBusWatch *watch,
359
unsigned int condition,
362
DBusBabysitter *sitter = data;
364
/* On Unix dbus-spawn uses a babysitter *process*, thus it has to
365
* actually send the exit statuses, error codes and whatnot through
366
* sockets and/or pipes. On Win32, the babysitter is jus a thread,
367
* so it can set the status fields directly in the babysitter struct
368
* just fine. The socket pipe is used just so we can watch it with
369
* select(), as soon as anything is written to it we know that the
370
* babysitter thread has recorded the status in the babysitter
375
_dbus_close_socket (sitter->socket_to_babysitter, NULL);
377
sitter->socket_to_babysitter = -1;
382
/* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */
384
protect_argv (char **argv,
392
*new_argv = dbus_malloc ((argc + 1) * sizeof (char *));
393
if (*new_argv == NULL)
396
for (i = 0; i < argc; i++)
397
(*new_argv)[i] = NULL;
399
/* Quote each argv element if necessary, so that it will get
400
* reconstructed correctly in the C runtime startup code. Note that
401
* the unquoting algorithm in the C runtime is really weird, and
402
* rather different than what Unix shells do. See stdargv.c in the C
403
* runtime sources (in the Platform SDK, in src/crt).
405
* Note that an new_argv[0] constructed by this function should
406
* *not* be passed as the filename argument to a spawn* or exec*
407
* family function. That argument should be the real file name
408
* without any quoting.
410
for (i = 0; i < argc; i++)
415
int need_dblquotes = FALSE;
418
if (*p == ' ' || *p == '\t')
419
need_dblquotes = TRUE;
425
while (*pp && *pp == '\\')
434
q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1);
452
while (*pp && *pp == '\\')
464
/* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */
466
(*new_argv)[argc] = NULL;
472
/* From GPGME, relicensed by g10 Code GmbH. */
474
compose_string (char **strings, char separator)
482
if (!strings || !strings[0])
484
for (i = 0; strings[i]; i++)
485
n += strlen (strings[i]) + 1;
488
buf = p = malloc (n);
491
for (i = 0; strings[i]; i++)
493
strcpy (p, strings[i]);
494
p += strlen (strings[i]);
505
build_commandline (char **argv)
507
return compose_string (argv, ' ');
511
build_env_string (char** envp)
513
return compose_string (envp, '\0');
517
spawn_program (char* name, char** argv, char** envp)
519
PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
521
char *arg_string, *env_string;
526
arg_string = build_commandline (argv + 1);
530
arg_string = build_commandline (argv);
533
return INVALID_HANDLE_VALUE;
535
env_string = build_env_string(envp);
537
memset (&si, 0, sizeof (si));
540
result = CreateProcessA (name, arg_string, NULL, NULL, FALSE, 0,
542
result = CreateProcessA (NULL, arg_string, NULL, NULL, FALSE, 0,
544
(LPVOID)env_string, NULL, &si, &pi);
550
return INVALID_HANDLE_VALUE;
552
CloseHandle (pi.hThread);
557
static DWORD __stdcall
558
babysitter (void *parameter)
560
DBusBabysitter *sitter = (DBusBabysitter *) parameter;
563
_dbus_babysitter_ref (sitter);
565
if (sitter->child_setup)
568
(*sitter->child_setup) (sitter->user_data);
571
_dbus_verbose ("babysitter: spawning %s\n", sitter->executable);
574
sitter->child_handle = spawn_program (sitter->executable,
575
sitter->argv, sitter->envp);
578
if (sitter->child_handle == (HANDLE) -1)
580
sitter->child_handle = NULL;
581
sitter->have_spawn_errno = TRUE;
582
sitter->spawn_errno = GetLastError();
586
SetEvent (sitter->start_sync_event);
588
if (sitter->child_handle != NULL)
594
WaitForSingleObject (sitter->child_handle, INFINITE);
597
ret = GetExitCodeProcess (sitter->child_handle, &status);
599
sitter->child_status = status;
600
sitter->have_child_status = TRUE;
602
CloseHandle (sitter->child_handle);
603
sitter->child_handle = NULL;
606
#ifdef DBUS_BUILD_TESTS
607
SetEvent (sitter->end_sync_event);
611
send (sitter->socket_to_main, " ", 1, 0);
613
_dbus_babysitter_unref (sitter);
619
_dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
622
DBusSpawnChildSetupFunc child_setup,
626
DBusBabysitter *sitter;
627
HANDLE sitter_thread;
628
DWORD sitter_thread_id;
630
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
635
sitter = _dbus_babysitter_new ();
638
_DBUS_SET_OOM (error);
642
sitter->child_setup = child_setup;
643
sitter->user_data = user_data;
645
sitter->executable = _dbus_strdup (argv[0]);
646
if (sitter->executable == NULL)
648
_DBUS_SET_OOM (error);
653
if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter,
654
&sitter->socket_to_main,
658
sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter,
660
TRUE, handle_watch, sitter, NULL);
662
if (sitter->sitter_watch == NULL)
664
_DBUS_SET_OOM (error);
669
if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
671
_DBUS_SET_OOM (error);
675
sitter->argc = protect_argv (argv, &sitter->argv);
676
if (sitter->argc == -1)
678
_DBUS_SET_OOM (error);
684
sitter_thread = (HANDLE) CreateThread (NULL, 0, babysitter,
685
sitter, 0, &sitter_thread_id);
687
if (sitter_thread == 0)
690
dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED,
691
"Failed to create new thread");
694
CloseHandle (sitter_thread);
697
WaitForSingleObject (sitter->start_sync_event, INFINITE);
700
if (sitter_p != NULL)
703
_dbus_babysitter_unref (sitter);
705
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
711
_dbus_babysitter_unref (sitter);
716
#ifdef DBUS_BUILD_TESTS
718
#define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)
721
_dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
723
if (sitter->child_handle == NULL)
726
WaitForSingleObject (sitter->end_sync_event, INFINITE);
730
check_spawn_nonexistent (void *data)
732
char *argv[4] = { NULL, NULL, NULL, NULL };
733
DBusBabysitter *sitter;
738
dbus_error_init (&error);
740
/*** Test launching nonexistent binary */
742
argv[0] = "/this/does/not/exist/32542sdgafgafdg";
743
if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
747
_dbus_babysitter_block_for_child_exit (sitter);
748
_dbus_babysitter_set_child_exit_error (sitter, &error);
752
_dbus_babysitter_unref (sitter);
754
if (!dbus_error_is_set (&error))
756
_dbus_warn ("Did not get an error launching nonexistent executable\n");
760
if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
761
dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
763
_dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
764
error.name, error.message);
765
dbus_error_free (&error);
769
dbus_error_free (&error);
775
check_spawn_segfault (void *data)
777
char *argv[4] = { NULL, NULL, NULL, NULL };
778
DBusBabysitter *sitter;
783
dbus_error_init (&error);
785
/*** Test launching segfault binary */
787
argv[0] = TEST_SEGFAULT_BINARY;
788
if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
792
_dbus_babysitter_block_for_child_exit (sitter);
793
_dbus_babysitter_set_child_exit_error (sitter, &error);
797
_dbus_babysitter_unref (sitter);
799
if (!dbus_error_is_set (&error))
801
_dbus_warn ("Did not get an error launching segfaulting binary\n");
805
if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
806
dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
808
_dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
809
error.name, error.message);
810
dbus_error_free (&error);
814
dbus_error_free (&error);
820
check_spawn_exit (void *data)
822
char *argv[4] = { NULL, NULL, NULL, NULL };
823
DBusBabysitter *sitter;
828
dbus_error_init (&error);
830
/*** Test launching exit failure binary */
832
argv[0] = TEST_EXIT_BINARY;
833
if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
837
_dbus_babysitter_block_for_child_exit (sitter);
838
_dbus_babysitter_set_child_exit_error (sitter, &error);
842
_dbus_babysitter_unref (sitter);
844
if (!dbus_error_is_set (&error))
846
_dbus_warn ("Did not get an error launching binary that exited with failure code\n");
850
if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
851
dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
853
_dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
854
error.name, error.message);
855
dbus_error_free (&error);
859
dbus_error_free (&error);
865
check_spawn_and_kill (void *data)
867
char *argv[4] = { NULL, NULL, NULL, NULL };
868
DBusBabysitter *sitter;
873
dbus_error_init (&error);
875
/*** Test launching sleeping binary then killing it */
877
argv[0] = TEST_SLEEP_FOREVER_BINARY;
878
if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
882
_dbus_babysitter_kill_child (sitter);
884
_dbus_babysitter_block_for_child_exit (sitter);
886
_dbus_babysitter_set_child_exit_error (sitter, &error);
890
_dbus_babysitter_unref (sitter);
892
if (!dbus_error_is_set (&error))
894
_dbus_warn ("Did not get an error after killing spawned binary\n");
898
if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
899
dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
901
_dbus_warn ("Not expecting error when killing executable: %s: %s\n",
902
error.name, error.message);
903
dbus_error_free (&error);
907
dbus_error_free (&error);
913
_dbus_spawn_test (const char *test_data_dir)
915
if (!_dbus_test_oom_handling ("spawn_nonexistent",
916
check_spawn_nonexistent,
920
/* Don't run the obnoxious segfault test by default,
921
* it's a pain to have to click all those error boxes.
923
if (getenv ("DO_SEGFAULT_TEST"))
924
if (!_dbus_test_oom_handling ("spawn_segfault",
925
check_spawn_segfault,
929
if (!_dbus_test_oom_handling ("spawn_exit",
934
if (!_dbus_test_oom_handling ("spawn_and_kill",
935
check_spawn_and_kill,