Windows CE has a different understanding of "command line" from Windows.
[platform/upstream/dbus.git] / dbus / dbus-spawn-win.c
1 #include <config.h>
2
3 //#define SPAWN_DEBUG
4
5 #if !defined(SPAWN_DEBUG) || defined(_MSC_VER)
6 #define PING()
7 #else
8 #define PING() fprintf (stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); fflush (stderr)
9 #endif
10
11 #include <stdio.h>
12 #ifdef DBUS_WINCE
13 #include <process.h>
14 #endif
15
16 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
17 /* dbus-spawn-win32.c Wrapper around g_spawn
18  * 
19  * Copyright (C) 2002, 2003, 2004  Red Hat, Inc.
20  * Copyright (C) 2003 CodeFactory AB
21  * Copyright (C) 2005 Novell, Inc.
22  *
23  * Licensed under the Academic Free License version 2.1
24  * 
25  * This program is free software; you can redistribute it and/or modify
26  * it under the terms of the GNU General Public License as published by
27  * the Free Software Foundation; either version 2 of the License, or
28  * (at your option) any later version.
29  *
30  * This program is distributed in the hope that it will be useful,
31  * but WITHOUT ANY WARRANTY; without even the implied warranty of
32  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33  * GNU General Public License for more details.
34  * 
35  * You should have received a copy of the GNU General Public License
36  * along with this program; if not, write to the Free Software
37  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
38  *
39  */
40 #include "dbus-spawn.h"
41 #include "dbus-sysdeps.h"
42 #include "dbus-sysdeps-win.h"
43 #include "dbus-internals.h"
44 #include "dbus-test.h"
45 #include "dbus-protocol.h"
46
47 #define WIN32_LEAN_AND_MEAN
48 //#define STRICT
49 //#include <windows.h>
50 //#undef STRICT
51 #include <winsock2.h>
52 #undef interface
53
54 #include <stdlib.h>
55
56 #include <process.h>
57
58 /**
59  * Babysitter implementation details
60  */
61 struct DBusBabysitter
62   {
63     int refcount;
64
65     HANDLE start_sync_event;
66 #ifdef DBUS_BUILD_TESTS
67
68     HANDLE end_sync_event;
69 #endif
70
71     char *executable;
72     DBusSpawnChildSetupFunc child_setup;
73     void *user_data;
74
75     int argc;
76     char **argv;
77     char **envp;
78
79     HANDLE child_handle;
80     int socket_to_babysitter;   /* Connection to the babysitter thread */
81     int socket_to_main;
82
83     DBusWatchList *watches;
84     DBusWatch *sitter_watch;
85
86     dbus_bool_t have_spawn_errno;
87     int spawn_errno;
88     dbus_bool_t have_child_status;
89     int child_status;
90   };
91
92 static DBusBabysitter*
93 _dbus_babysitter_new (void)
94 {
95   DBusBabysitter *sitter;
96
97   sitter = dbus_new0 (DBusBabysitter, 1);
98   if (sitter == NULL)
99     return NULL;
100
101   sitter->refcount = 1;
102
103   sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
104   if (sitter->start_sync_event == NULL)
105     {
106       _dbus_babysitter_unref (sitter);
107       return NULL;
108     }
109
110 #ifdef DBUS_BUILD_TESTS
111   sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
112   if (sitter->end_sync_event == NULL)
113     {
114       _dbus_babysitter_unref (sitter);
115       return NULL;
116     }
117 #endif
118
119   sitter->child_handle = NULL;
120
121   sitter->socket_to_babysitter = sitter->socket_to_main = -1;
122
123   sitter->argc = 0;
124   sitter->argv = NULL;
125   sitter->envp = NULL;
126
127   sitter->watches = _dbus_watch_list_new ();
128   if (sitter->watches == NULL)
129     {
130       _dbus_babysitter_unref (sitter);
131       return NULL;
132     }
133
134   sitter->have_spawn_errno = FALSE;
135   sitter->have_child_status = FALSE;
136
137   return sitter;
138 }
139
140 /**
141  * Increment the reference count on the babysitter object.
142  *
143  * @param sitter the babysitter
144  * @returns the babysitter
145  */
146 DBusBabysitter *
147 _dbus_babysitter_ref (DBusBabysitter *sitter)
148 {
149   PING();
150   _dbus_assert (sitter != NULL);
151   _dbus_assert (sitter->refcount > 0);
152
153   sitter->refcount += 1;
154
155   return sitter;
156 }
157
158 /**
159  * Decrement the reference count on the babysitter object.
160  *
161  * @param sitter the babysitter
162  */
163 void
164 _dbus_babysitter_unref (DBusBabysitter *sitter)
165 {
166   int i;
167
168   PING();
169   _dbus_assert (sitter != NULL);
170   _dbus_assert (sitter->refcount > 0);
171
172   sitter->refcount -= 1;
173
174   if (sitter->refcount == 0)
175     {
176       if (sitter->socket_to_babysitter != -1)
177         {
178           _dbus_close_socket (sitter->socket_to_babysitter, NULL);
179           sitter->socket_to_babysitter = -1;
180         }
181
182       if (sitter->socket_to_main != -1)
183         {
184           _dbus_close_socket (sitter->socket_to_main, NULL);
185           sitter->socket_to_main = -1;
186         }
187
188       PING();
189       if (sitter->argv != NULL)
190         {
191           for (i = 0; i < sitter->argc; i++)
192             if (sitter->argv[i] != NULL)
193               {
194                 dbus_free (sitter->argv[i]);
195                 sitter->argv[i] = NULL;
196               }
197           dbus_free (sitter->argv);
198           sitter->argv = NULL;
199         }
200
201       if (sitter->envp != NULL)
202         {
203           char **e = sitter->envp;
204
205           while (*e)
206             dbus_free (*e++);
207           dbus_free (sitter->envp);
208           sitter->envp = NULL;
209         }
210
211       if (sitter->child_handle != NULL)
212         {
213           CloseHandle (sitter->child_handle);
214           sitter->child_handle = NULL;
215         }
216
217       if (sitter->sitter_watch)
218         {
219           _dbus_watch_invalidate (sitter->sitter_watch);
220           _dbus_watch_unref (sitter->sitter_watch);
221           sitter->sitter_watch = NULL;
222         }
223
224       if (sitter->watches)
225         _dbus_watch_list_free (sitter->watches);
226
227       if (sitter->start_sync_event != NULL)
228         {
229           PING();
230           CloseHandle (sitter->start_sync_event);
231           sitter->start_sync_event = NULL;
232         }
233
234 #ifdef DBUS_BUILD_TESTS
235       if (sitter->end_sync_event != NULL)
236         {
237           CloseHandle (sitter->end_sync_event);
238           sitter->end_sync_event = NULL;
239         }
240 #endif
241
242       dbus_free (sitter->executable);
243
244       dbus_free (sitter);
245     }
246 }
247
248 void
249 _dbus_babysitter_kill_child (DBusBabysitter *sitter)
250 {
251   PING();
252   if (sitter->child_handle == NULL)
253     return; /* child is already dead, or we're so hosed we'll never recover */
254
255   PING();
256   TerminateProcess (sitter->child_handle, 12345);
257 }
258
259 /**
260  * Checks whether the child has exited, without blocking.
261  *
262  * @param sitter the babysitter
263  */
264 dbus_bool_t
265 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
266 {
267   PING();
268   return (sitter->child_handle == NULL);
269 }
270
271 /**
272  * Gets the exit status of the child. We do this so implementation specific
273  * detail is not cluttering up dbus, for example the system launcher code.
274  * This can only be called if the child has exited, i.e. call
275  * _dbus_babysitter_get_child_exited(). It returns FALSE if the child
276  * did not return a status code, e.g. because the child was signaled
277  * or we failed to ever launch the child in the first place.
278  *
279  * @param sitter the babysitter
280  * @param status the returned status code
281  * @returns #FALSE on failure
282  */
283 dbus_bool_t
284 _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter,
285                                         int            *status)
286 {
287   if (!_dbus_babysitter_get_child_exited (sitter))
288     _dbus_assert_not_reached ("Child has not exited");
289
290   if (!sitter->have_child_status ||
291       sitter->child_status == STILL_ACTIVE)
292     return FALSE;
293
294   *status = sitter->child_status;
295   return TRUE;
296 }
297
298 /**
299  * Sets the #DBusError with an explanation of why the spawned
300  * child process exited (on a signal, or whatever). If
301  * the child process has not exited, does nothing (error
302  * will remain unset).
303  *
304  * @param sitter the babysitter
305  * @param error an error to fill in
306  */
307 void
308 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
309                                        DBusError      *error)
310 {
311   PING();
312   if (!_dbus_babysitter_get_child_exited (sitter))
313     return;
314
315   PING();
316   if (sitter->have_spawn_errno)
317     {
318       char *emsg = _dbus_win_error_string (sitter->spawn_errno);
319       dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
320                       "Failed to execute program %s: %s",
321                       sitter->executable, emsg);
322       _dbus_win_free_error_string (emsg);
323     }
324   else if (sitter->have_child_status)
325     {
326       PING();
327       dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
328                       "Process %s exited with status %d",
329                       sitter->executable, sitter->child_status);
330     }
331   else
332     {
333       PING();
334       dbus_set_error (error, DBUS_ERROR_FAILED,
335                       "Process %s exited, status unknown",
336                       sitter->executable);
337     }
338   PING();
339 }
340
341 dbus_bool_t
342 _dbus_babysitter_set_watch_functions (DBusBabysitter            *sitter,
343                                       DBusAddWatchFunction       add_function,
344                                       DBusRemoveWatchFunction    remove_function,
345                                       DBusWatchToggledFunction   toggled_function,
346                                       void                      *data,
347                                       DBusFreeFunction           free_data_function)
348 {
349   PING();
350   return _dbus_watch_list_set_functions (sitter->watches,
351                                          add_function,
352                                          remove_function,
353                                          toggled_function,
354                                          data,
355                                          free_data_function);
356 }
357
358 static dbus_bool_t
359 handle_watch (DBusWatch       *watch,
360               unsigned int     condition,
361               void            *data)
362 {
363   DBusBabysitter *sitter = data;
364
365   /* On Unix dbus-spawn uses a babysitter *process*, thus it has to
366    * actually send the exit statuses, error codes and whatnot through
367    * sockets and/or pipes. On Win32, the babysitter is jus a thread,
368    * so it can set the status fields directly in the babysitter struct
369    * just fine. The socket pipe is used just so we can watch it with
370    * select(), as soon as anything is written to it we know that the
371    * babysitter thread has recorded the status in the babysitter
372    * struct.
373    */
374
375   PING();
376   _dbus_close_socket (sitter->socket_to_babysitter, NULL);
377   PING();
378   sitter->socket_to_babysitter = -1;
379
380   return TRUE;
381 }
382
383 /* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */
384 static int
385 protect_argv (char  **argv,
386               char ***new_argv)
387 {
388   int i;
389   int argc = 0;
390
391   while (argv[argc])
392     ++argc;
393   *new_argv = dbus_malloc ((argc + 1) * sizeof (char *));
394   if (*new_argv == NULL)
395     return -1;
396
397   for (i = 0; i < argc; i++)
398     (*new_argv)[i] = NULL;
399
400   /* Quote each argv element if necessary, so that it will get
401    * reconstructed correctly in the C runtime startup code.  Note that
402    * the unquoting algorithm in the C runtime is really weird, and
403    * rather different than what Unix shells do. See stdargv.c in the C
404    * runtime sources (in the Platform SDK, in src/crt).
405    *
406    * Note that an new_argv[0] constructed by this function should
407    * *not* be passed as the filename argument to a spawn* or exec*
408    * family function. That argument should be the real file name
409    * without any quoting.
410    */
411   for (i = 0; i < argc; i++)
412     {
413       char *p = argv[i];
414       char *q;
415       int len = 0;
416       int need_dblquotes = FALSE;
417       while (*p)
418         {
419           if (*p == ' ' || *p == '\t')
420             need_dblquotes = TRUE;
421           else if (*p == '"')
422             len++;
423           else if (*p == '\\')
424             {
425               char *pp = p;
426               while (*pp && *pp == '\\')
427                 pp++;
428               if (*pp == '"')
429                 len++;
430             }
431           len++;
432           p++;
433         }
434
435       q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1);
436
437       if (q == NULL)
438         return -1;
439
440
441       p = argv[i];
442
443       if (need_dblquotes)
444         *q++ = '"';
445
446       while (*p)
447         {
448           if (*p == '"')
449             *q++ = '\\';
450           else if (*p == '\\')
451             {
452               char *pp = p;
453               while (*pp && *pp == '\\')
454                 pp++;
455               if (*pp == '"')
456                 *q++ = '\\';
457             }
458           *q++ = *p;
459           p++;
460         }
461
462       if (need_dblquotes)
463         *q++ = '"';
464       *q++ = '\0';
465       /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */
466     }
467   (*new_argv)[argc] = NULL;
468
469   return argc;
470 }
471
472
473 /* From GPGME, relicensed by g10 Code GmbH.  */
474 static char *
475 build_commandline (char **argv)
476 {
477   int i;
478   int n = 0;
479   char *buf;
480   char *p;
481   const char *ptr;
482   
483   for (i = 0; argv[i]; i++)
484     n += strlen (argv[i]) + 1;
485   n++;
486
487   buf = p = malloc (n);
488   if (!buf)
489     return NULL;
490   for (i = 0; argv[i]; i++)
491     {
492       strcpy (p, argv[i]);
493       p += strlen (argv[i]);
494       *(p++) = ' ';
495     }
496   if (i)
497     p--;
498   *p = '\0';
499
500   return buf;
501 }
502
503
504 static HANDLE
505 spawn_program (const char* name, char** argv, char** envp)
506 {
507   PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
508   STARTUPINFOA si;
509   char *arg_string;
510   BOOL result;
511
512 #ifdef DBUS_WINCE
513   arg_string = build_commandline (argv + 1);
514 #else
515   arg_string = build_commandline (argv);
516 #endif
517   if (!arg_string)
518     return INVALID_HANDLE_VALUE;
519
520   memset (&si, 0, sizeof (si));
521   si.cb = sizeof (si);
522   result = CreateProcessA (name, arg_string, NULL, NULL, FALSE, 0,
523                            envp, NULL, &si, &pi);
524   free (arg_string);
525   if (!result)
526     return INVALID_HANDLE_VALUE;
527
528   CloseHandle (pi.hThread);
529   return pi.hProcess;
530 }
531
532
533 static DWORD __stdcall
534 babysitter (void *parameter)
535 {
536   DBusBabysitter *sitter = (DBusBabysitter *) parameter;
537   int fd;
538   PING();
539   _dbus_babysitter_ref (sitter);
540
541   if (sitter->child_setup)
542     {
543       PING();
544       (*sitter->child_setup) (sitter->user_data);
545     }
546
547   _dbus_verbose ("babysitter: spawning %s\n", sitter->executable);
548
549   PING();
550   sitter->child_handle = spawn_program (sitter->executable,
551                                         sitter->argv, sitter->envp);
552
553   PING();
554   if (sitter->child_handle == (HANDLE) -1)
555     {
556       sitter->child_handle = NULL;
557       sitter->have_spawn_errno = TRUE;
558       sitter->spawn_errno = GetLastError();
559     }
560   
561   PING();
562   SetEvent (sitter->start_sync_event);
563
564   if (sitter->child_handle != NULL)
565     {
566       int ret;
567       DWORD status;
568
569       PING();
570       WaitForSingleObject (sitter->child_handle, INFINITE);
571
572       PING();
573       ret = GetExitCodeProcess (sitter->child_handle, &status);
574
575       sitter->child_status = status;
576       sitter->have_child_status = TRUE;
577
578       CloseHandle (sitter->child_handle);
579       sitter->child_handle = NULL;
580     }
581
582 #ifdef DBUS_BUILD_TESTS
583   SetEvent (sitter->end_sync_event);
584 #endif
585
586   PING();
587   send (sitter->socket_to_main, " ", 1, 0);
588
589   _dbus_babysitter_unref (sitter);
590
591   return 0;
592 }
593
594 dbus_bool_t
595 _dbus_spawn_async_with_babysitter (DBusBabysitter           **sitter_p,
596                                    char                     **argv,
597                                    char                     **envp,
598                                    DBusSpawnChildSetupFunc    child_setup,
599                                    void                      *user_data,
600                                    DBusError                 *error)
601 {
602   DBusBabysitter *sitter;
603   HANDLE sitter_thread;
604   DWORD sitter_thread_id;
605   
606   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
607
608   *sitter_p = NULL;
609
610   PING();
611   sitter = _dbus_babysitter_new ();
612   if (sitter == NULL)
613     {
614       _DBUS_SET_OOM (error);
615       return FALSE;
616     }
617
618   sitter->child_setup = child_setup;
619   sitter->user_data = user_data;
620
621   sitter->executable = _dbus_strdup (argv[0]);
622   if (sitter->executable == NULL)
623     {
624       _DBUS_SET_OOM (error);
625       goto out0;
626     }
627
628   PING();
629   if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter,
630                                &sitter->socket_to_main,
631                                FALSE, error))
632     goto out0;
633
634   sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter,
635                                           DBUS_WATCH_READABLE,
636                                           TRUE, handle_watch, sitter, NULL);
637   PING();
638   if (sitter->sitter_watch == NULL)
639     {
640       _DBUS_SET_OOM (error);
641       goto out0;
642     }
643
644   PING();
645   if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
646     {
647       _DBUS_SET_OOM (error);
648       goto out0;
649     }
650
651   sitter->argc = protect_argv (argv, &sitter->argv);
652   if (sitter->argc == -1)
653     {
654       _DBUS_SET_OOM (error);
655       goto out0;
656     }
657   sitter->envp = envp;
658
659   PING();
660   sitter_thread = (HANDLE) CreateThread (NULL, 0, babysitter,
661                   sitter, 0, &sitter_thread_id);
662
663   if (sitter_thread == 0)
664     {
665       PING();
666       dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED,
667                             "Failed to create new thread");
668       goto out0;
669     }
670   CloseHandle (sitter_thread);
671
672   PING();
673   WaitForSingleObject (sitter->start_sync_event, INFINITE);
674
675   PING();
676   if (sitter_p != NULL)
677     *sitter_p = sitter;
678   else
679     _dbus_babysitter_unref (sitter);
680
681   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
682
683   PING();
684   return TRUE;
685
686 out0:
687   _dbus_babysitter_unref (sitter);
688
689   return FALSE;
690 }
691
692 #ifdef DBUS_BUILD_TESTS
693
694 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)
695
696 static void
697 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
698 {
699   if (sitter->child_handle == NULL)
700     return;
701
702   WaitForSingleObject (sitter->end_sync_event, INFINITE);
703 }
704
705 static dbus_bool_t
706 check_spawn_nonexistent (void *data)
707 {
708   char *argv[4] = { NULL, NULL, NULL, NULL };
709   DBusBabysitter *sitter;
710   DBusError error;
711
712   sitter = NULL;
713
714   dbus_error_init (&error);
715
716   /*** Test launching nonexistent binary */
717
718   argv[0] = "/this/does/not/exist/32542sdgafgafdg";
719   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
720                                          NULL, NULL,
721                                          &error))
722     {
723       _dbus_babysitter_block_for_child_exit (sitter);
724       _dbus_babysitter_set_child_exit_error (sitter, &error);
725     }
726
727   if (sitter)
728     _dbus_babysitter_unref (sitter);
729
730   if (!dbus_error_is_set (&error))
731     {
732       _dbus_warn ("Did not get an error launching nonexistent executable\n");
733       return FALSE;
734     }
735
736   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
737         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
738     {
739       _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
740                   error.name, error.message);
741       dbus_error_free (&error);
742       return FALSE;
743     }
744
745   dbus_error_free (&error);
746
747   return TRUE;
748 }
749
750 static dbus_bool_t
751 check_spawn_segfault (void *data)
752 {
753   char *argv[4] = { NULL, NULL, NULL, NULL };
754   DBusBabysitter *sitter;
755   DBusError error;
756
757   sitter = NULL;
758
759   dbus_error_init (&error);
760
761   /*** Test launching segfault binary */
762
763   argv[0] = TEST_SEGFAULT_BINARY;
764   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
765                                          NULL, NULL,
766                                          &error))
767     {
768       _dbus_babysitter_block_for_child_exit (sitter);
769       _dbus_babysitter_set_child_exit_error (sitter, &error);
770     }
771
772   if (sitter)
773     _dbus_babysitter_unref (sitter);
774
775   if (!dbus_error_is_set (&error))
776     {
777       _dbus_warn ("Did not get an error launching segfaulting binary\n");
778       return FALSE;
779     }
780
781   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
782         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
783     {
784       _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
785                   error.name, error.message);
786       dbus_error_free (&error);
787       return FALSE;
788     }
789
790   dbus_error_free (&error);
791
792   return TRUE;
793 }
794
795 static dbus_bool_t
796 check_spawn_exit (void *data)
797 {
798   char *argv[4] = { NULL, NULL, NULL, NULL };
799   DBusBabysitter *sitter;
800   DBusError error;
801
802   sitter = NULL;
803
804   dbus_error_init (&error);
805
806   /*** Test launching exit failure binary */
807
808   argv[0] = TEST_EXIT_BINARY;
809   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
810                                          NULL, NULL,
811                                          &error))
812     {
813       _dbus_babysitter_block_for_child_exit (sitter);
814       _dbus_babysitter_set_child_exit_error (sitter, &error);
815     }
816
817   if (sitter)
818     _dbus_babysitter_unref (sitter);
819
820   if (!dbus_error_is_set (&error))
821     {
822       _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
823       return FALSE;
824     }
825
826   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
827         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
828     {
829       _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
830                   error.name, error.message);
831       dbus_error_free (&error);
832       return FALSE;
833     }
834
835   dbus_error_free (&error);
836
837   return TRUE;
838 }
839
840 static dbus_bool_t
841 check_spawn_and_kill (void *data)
842 {
843   char *argv[4] = { NULL, NULL, NULL, NULL };
844   DBusBabysitter *sitter;
845   DBusError error;
846
847   sitter = NULL;
848
849   dbus_error_init (&error);
850
851   /*** Test launching sleeping binary then killing it */
852
853   argv[0] = TEST_SLEEP_FOREVER_BINARY;
854   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
855                                          NULL, NULL,
856                                          &error))
857     {
858       _dbus_babysitter_kill_child (sitter);
859
860       _dbus_babysitter_block_for_child_exit (sitter);
861
862       _dbus_babysitter_set_child_exit_error (sitter, &error);
863     }
864
865   if (sitter)
866     _dbus_babysitter_unref (sitter);
867
868   if (!dbus_error_is_set (&error))
869     {
870       _dbus_warn ("Did not get an error after killing spawned binary\n");
871       return FALSE;
872     }
873
874   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
875         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
876     {
877       _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
878                   error.name, error.message);
879       dbus_error_free (&error);
880       return FALSE;
881     }
882
883   dbus_error_free (&error);
884
885   return TRUE;
886 }
887
888 dbus_bool_t
889 _dbus_spawn_test (const char *test_data_dir)
890 {
891   if (!_dbus_test_oom_handling ("spawn_nonexistent",
892                                 check_spawn_nonexistent,
893                                 NULL))
894     return FALSE;
895
896   /* Don't run the obnoxious segfault test by default,
897    * it's a pain to have to click all those error boxes.
898    */
899   if (getenv ("DO_SEGFAULT_TEST"))
900     if (!_dbus_test_oom_handling ("spawn_segfault",
901                                   check_spawn_segfault,
902                                   NULL))
903       return FALSE;
904
905   if (!_dbus_test_oom_handling ("spawn_exit",
906                                 check_spawn_exit,
907                                 NULL))
908     return FALSE;
909
910   if (!_dbus_test_oom_handling ("spawn_and_kill",
911                                 check_spawn_and_kill,
912                                 NULL))
913     return FALSE;
914
915   return TRUE;
916 }
917 #endif