Merge branch 'dbus-1.2'
[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       dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
319                       "Failed to execute program %s: %s",
320                       sitter->executable, _dbus_strerror (sitter->spawn_errno));
321     }
322   else if (sitter->have_child_status)
323     {
324       PING();
325       dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
326                       "Process %s exited with status %d",
327                       sitter->executable, sitter->child_status);
328     }
329   else
330     {
331       PING();
332       dbus_set_error (error, DBUS_ERROR_FAILED,
333                       "Process %s exited, status unknown",
334                       sitter->executable);
335     }
336   PING();
337 }
338
339 dbus_bool_t
340 _dbus_babysitter_set_watch_functions (DBusBabysitter            *sitter,
341                                       DBusAddWatchFunction       add_function,
342                                       DBusRemoveWatchFunction    remove_function,
343                                       DBusWatchToggledFunction   toggled_function,
344                                       void                      *data,
345                                       DBusFreeFunction           free_data_function)
346 {
347   PING();
348   return _dbus_watch_list_set_functions (sitter->watches,
349                                          add_function,
350                                          remove_function,
351                                          toggled_function,
352                                          data,
353                                          free_data_function);
354 }
355
356 static dbus_bool_t
357 handle_watch (DBusWatch       *watch,
358               unsigned int     condition,
359               void            *data)
360 {
361   DBusBabysitter *sitter = data;
362
363   /* On Unix dbus-spawn uses a babysitter *process*, thus it has to
364    * actually send the exit statuses, error codes and whatnot through
365    * sockets and/or pipes. On Win32, the babysitter is jus a thread,
366    * so it can set the status fields directly in the babysitter struct
367    * just fine. The socket pipe is used just so we can watch it with
368    * select(), as soon as anything is written to it we know that the
369    * babysitter thread has recorded the status in the babysitter
370    * struct.
371    */
372
373   PING();
374   _dbus_close_socket (sitter->socket_to_babysitter, NULL);
375   PING();
376   sitter->socket_to_babysitter = -1;
377
378   return TRUE;
379 }
380
381 /* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */
382 static int
383 protect_argv (char  **argv,
384               char ***new_argv)
385 {
386   int i;
387   int argc = 0;
388
389   while (argv[argc])
390     ++argc;
391   *new_argv = dbus_malloc ((argc + 1) * sizeof (char *));
392   if (*new_argv == NULL)
393     return -1;
394
395   for (i = 0; i < argc; i++)
396     (*new_argv)[i] = NULL;
397
398   /* Quote each argv element if necessary, so that it will get
399    * reconstructed correctly in the C runtime startup code.  Note that
400    * the unquoting algorithm in the C runtime is really weird, and
401    * rather different than what Unix shells do. See stdargv.c in the C
402    * runtime sources (in the Platform SDK, in src/crt).
403    *
404    * Note that an new_argv[0] constructed by this function should
405    * *not* be passed as the filename argument to a spawn* or exec*
406    * family function. That argument should be the real file name
407    * without any quoting.
408    */
409   for (i = 0; i < argc; i++)
410     {
411       char *p = argv[i];
412       char *q;
413       int len = 0;
414       int need_dblquotes = FALSE;
415       while (*p)
416         {
417           if (*p == ' ' || *p == '\t')
418             need_dblquotes = TRUE;
419           else if (*p == '"')
420             len++;
421           else if (*p == '\\')
422             {
423               char *pp = p;
424               while (*pp && *pp == '\\')
425                 pp++;
426               if (*pp == '"')
427                 len++;
428             }
429           len++;
430           p++;
431         }
432
433       q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1);
434
435       if (q == NULL)
436         return -1;
437
438
439       p = argv[i];
440
441       if (need_dblquotes)
442         *q++ = '"';
443
444       while (*p)
445         {
446           if (*p == '"')
447             *q++ = '\\';
448           else if (*p == '\\')
449             {
450               char *pp = p;
451               while (*pp && *pp == '\\')
452                 pp++;
453               if (*pp == '"')
454                 *q++ = '\\';
455             }
456           *q++ = *p;
457           p++;
458         }
459
460       if (need_dblquotes)
461         *q++ = '"';
462       *q++ = '\0';
463       /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */
464     }
465   (*new_argv)[argc] = NULL;
466
467   return argc;
468 }
469
470 static unsigned __stdcall
471 babysitter (void *parameter)
472 {
473   DBusBabysitter *sitter = (DBusBabysitter *) parameter;
474   int fd;
475   PING();
476   _dbus_babysitter_ref (sitter);
477
478   if (sitter->child_setup)
479     {
480       PING();
481       (*sitter->child_setup) (sitter->user_data);
482     }
483
484   _dbus_verbose ("babysitter: spawning %s\n", sitter->executable);
485
486   PING();
487   if (sitter->envp != NULL)
488     sitter->child_handle = (HANDLE) spawnve (P_NOWAIT, sitter->executable,
489                            (const char * const *) sitter->argv,
490                            (const char * const *) sitter->envp);
491   else
492     sitter->child_handle = (HANDLE) spawnv (P_NOWAIT, sitter->executable,
493                                             (const char * const *) sitter->argv);
494
495   PING();
496   if (sitter->child_handle == (HANDLE) -1)
497     {
498       sitter->child_handle = NULL;
499       sitter->have_spawn_errno = TRUE;
500       sitter->spawn_errno = errno;
501     }
502
503   PING();
504   SetEvent (sitter->start_sync_event);
505
506   if (sitter->child_handle != NULL)
507     {
508       int ret;
509       DWORD status;
510
511       PING();
512       WaitForSingleObject (sitter->child_handle, INFINITE);
513
514       PING();
515       ret = GetExitCodeProcess (sitter->child_handle, &status);
516
517       sitter->child_status = status;
518       sitter->have_child_status = TRUE;
519
520       CloseHandle (sitter->child_handle);
521       sitter->child_handle = NULL;
522     }
523
524 #ifdef DBUS_BUILD_TESTS
525   SetEvent (sitter->end_sync_event);
526 #endif
527
528   PING();
529   send (sitter->socket_to_main, " ", 1, 0);
530
531   _dbus_babysitter_unref (sitter);
532
533   return 0;
534 }
535
536 dbus_bool_t
537 _dbus_spawn_async_with_babysitter (DBusBabysitter           **sitter_p,
538                                    char                     **argv,
539                                    char                     **envp,
540                                    DBusSpawnChildSetupFunc    child_setup,
541                                    void                      *user_data,
542                                    DBusError                 *error)
543 {
544   DBusBabysitter *sitter;
545   HANDLE sitter_thread;
546   int sitter_thread_id;
547
548   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
549
550   *sitter_p = NULL;
551
552   PING();
553   sitter = _dbus_babysitter_new ();
554   if (sitter == NULL)
555     {
556       _DBUS_SET_OOM (error);
557       return FALSE;
558     }
559
560   sitter->child_setup = child_setup;
561   sitter->user_data = user_data;
562
563   sitter->executable = _dbus_strdup (argv[0]);
564   if (sitter->executable == NULL)
565     {
566       _DBUS_SET_OOM (error);
567       goto out0;
568     }
569
570   PING();
571   if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter,
572                                &sitter->socket_to_main,
573                                FALSE, error))
574     goto out0;
575
576   sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter,
577                                           DBUS_WATCH_READABLE,
578                                           TRUE, handle_watch, sitter, NULL);
579   PING();
580   if (sitter->sitter_watch == NULL)
581     {
582       _DBUS_SET_OOM (error);
583       goto out0;
584     }
585
586   PING();
587   if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
588     {
589       _DBUS_SET_OOM (error);
590       goto out0;
591     }
592
593   sitter->argc = protect_argv (argv, &sitter->argv);
594   if (sitter->argc == -1)
595     {
596       _DBUS_SET_OOM (error);
597       goto out0;
598     }
599   sitter->envp = envp;
600
601   PING();
602   sitter_thread = (HANDLE) _beginthreadex (NULL, 0, babysitter,
603                   sitter, 0, &sitter_thread_id);
604
605   if (sitter_thread == 0)
606     {
607       PING();
608       dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED,
609                             "Failed to create new thread");
610       goto out0;
611     }
612   CloseHandle (sitter_thread);
613
614   PING();
615   WaitForSingleObject (sitter->start_sync_event, INFINITE);
616
617   PING();
618   if (sitter_p != NULL)
619     *sitter_p = sitter;
620   else
621     _dbus_babysitter_unref (sitter);
622
623   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
624
625   PING();
626   return TRUE;
627
628 out0:
629   _dbus_babysitter_unref (sitter);
630
631   return FALSE;
632 }
633
634 #ifdef DBUS_BUILD_TESTS
635
636 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)
637
638 static void
639 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
640 {
641   if (sitter->child_handle == NULL)
642     return;
643
644   WaitForSingleObject (sitter->end_sync_event, INFINITE);
645 }
646
647 static dbus_bool_t
648 check_spawn_nonexistent (void *data)
649 {
650   char *argv[4] = { NULL, NULL, NULL, NULL };
651   DBusBabysitter *sitter;
652   DBusError error;
653
654   sitter = NULL;
655
656   dbus_error_init (&error);
657
658   /*** Test launching nonexistent binary */
659
660   argv[0] = "/this/does/not/exist/32542sdgafgafdg";
661   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
662                                          NULL, NULL,
663                                          &error))
664     {
665       _dbus_babysitter_block_for_child_exit (sitter);
666       _dbus_babysitter_set_child_exit_error (sitter, &error);
667     }
668
669   if (sitter)
670     _dbus_babysitter_unref (sitter);
671
672   if (!dbus_error_is_set (&error))
673     {
674       _dbus_warn ("Did not get an error launching nonexistent executable\n");
675       return FALSE;
676     }
677
678   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
679         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
680     {
681       _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
682                   error.name, error.message);
683       dbus_error_free (&error);
684       return FALSE;
685     }
686
687   dbus_error_free (&error);
688
689   return TRUE;
690 }
691
692 static dbus_bool_t
693 check_spawn_segfault (void *data)
694 {
695   char *argv[4] = { NULL, NULL, NULL, NULL };
696   DBusBabysitter *sitter;
697   DBusError error;
698
699   sitter = NULL;
700
701   dbus_error_init (&error);
702
703   /*** Test launching segfault binary */
704
705   argv[0] = TEST_SEGFAULT_BINARY;
706   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
707                                          NULL, NULL,
708                                          &error))
709     {
710       _dbus_babysitter_block_for_child_exit (sitter);
711       _dbus_babysitter_set_child_exit_error (sitter, &error);
712     }
713
714   if (sitter)
715     _dbus_babysitter_unref (sitter);
716
717   if (!dbus_error_is_set (&error))
718     {
719       _dbus_warn ("Did not get an error launching segfaulting binary\n");
720       return FALSE;
721     }
722
723   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
724         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
725     {
726       _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
727                   error.name, error.message);
728       dbus_error_free (&error);
729       return FALSE;
730     }
731
732   dbus_error_free (&error);
733
734   return TRUE;
735 }
736
737 static dbus_bool_t
738 check_spawn_exit (void *data)
739 {
740   char *argv[4] = { NULL, NULL, NULL, NULL };
741   DBusBabysitter *sitter;
742   DBusError error;
743
744   sitter = NULL;
745
746   dbus_error_init (&error);
747
748   /*** Test launching exit failure binary */
749
750   argv[0] = TEST_EXIT_BINARY;
751   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
752                                          NULL, NULL,
753                                          &error))
754     {
755       _dbus_babysitter_block_for_child_exit (sitter);
756       _dbus_babysitter_set_child_exit_error (sitter, &error);
757     }
758
759   if (sitter)
760     _dbus_babysitter_unref (sitter);
761
762   if (!dbus_error_is_set (&error))
763     {
764       _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
765       return FALSE;
766     }
767
768   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
769         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
770     {
771       _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
772                   error.name, error.message);
773       dbus_error_free (&error);
774       return FALSE;
775     }
776
777   dbus_error_free (&error);
778
779   return TRUE;
780 }
781
782 static dbus_bool_t
783 check_spawn_and_kill (void *data)
784 {
785   char *argv[4] = { NULL, NULL, NULL, NULL };
786   DBusBabysitter *sitter;
787   DBusError error;
788
789   sitter = NULL;
790
791   dbus_error_init (&error);
792
793   /*** Test launching sleeping binary then killing it */
794
795   argv[0] = TEST_SLEEP_FOREVER_BINARY;
796   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
797                                          NULL, NULL,
798                                          &error))
799     {
800       _dbus_babysitter_kill_child (sitter);
801
802       _dbus_babysitter_block_for_child_exit (sitter);
803
804       _dbus_babysitter_set_child_exit_error (sitter, &error);
805     }
806
807   if (sitter)
808     _dbus_babysitter_unref (sitter);
809
810   if (!dbus_error_is_set (&error))
811     {
812       _dbus_warn ("Did not get an error after killing spawned binary\n");
813       return FALSE;
814     }
815
816   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
817         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
818     {
819       _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
820                   error.name, error.message);
821       dbus_error_free (&error);
822       return FALSE;
823     }
824
825   dbus_error_free (&error);
826
827   return TRUE;
828 }
829
830 dbus_bool_t
831 _dbus_spawn_test (const char *test_data_dir)
832 {
833   if (!_dbus_test_oom_handling ("spawn_nonexistent",
834                                 check_spawn_nonexistent,
835                                 NULL))
836     return FALSE;
837
838   /* Don't run the obnoxious segfault test by default,
839    * it's a pain to have to click all those error boxes.
840    */
841   if (getenv ("DO_SEGFAULT_TEST"))
842     if (!_dbus_test_oom_handling ("spawn_segfault",
843                                   check_spawn_segfault,
844                                   NULL))
845       return FALSE;
846
847   if (!_dbus_test_oom_handling ("spawn_exit",
848                                 check_spawn_exit,
849                                 NULL))
850     return FALSE;
851
852   if (!_dbus_test_oom_handling ("spawn_and_kill",
853                                 check_spawn_and_kill,
854                                 NULL))
855     return FALSE;
856
857   return TRUE;
858 }
859 #endif