dbus-spawn-win.c

00001 #include "config.h"
00002 
00003 //#define SPAWN_DEBUG
00004 
00005 #if !defined(SPAWN_DEBUG) || defined(_MSC_VER)
00006 #define PING()
00007 #else
00008 #define PING() fprintf (stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); fflush (stderr)
00009 #endif
00010 
00011 #include <stdio.h>
00012 #ifdef DBUS_WINCE
00013 #include <process.h>
00014 #endif
00015 
00016 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00017 /* dbus-spawn-win32.c Wrapper around g_spawn
00018  * 
00019  * Copyright (C) 2002, 2003, 2004  Red Hat, Inc.
00020  * Copyright (C) 2003 CodeFactory AB
00021  * Copyright (C) 2005 Novell, Inc.
00022  *
00023  * Licensed under the Academic Free License version 2.1
00024  * 
00025  * This program is free software; you can redistribute it and/or modify
00026  * it under the terms of the GNU General Public License as published by
00027  * the Free Software Foundation; either version 2 of the License, or
00028  * (at your option) any later version.
00029  *
00030  * This program is distributed in the hope that it will be useful,
00031  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00032  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00033  * GNU General Public License for more details.
00034  * 
00035  * You should have received a copy of the GNU General Public License
00036  * along with this program; if not, write to the Free Software
00037  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00038  *
00039  */
00040 #include "dbus-spawn.h"
00041 #include "dbus-sysdeps.h"
00042 #include "dbus-sysdeps-win.h"
00043 #include "dbus-internals.h"
00044 #include "dbus-test.h"
00045 #include "dbus-protocol.h"
00046 
00047 #define WIN32_LEAN_AND_MEAN
00048 //#define STRICT
00049 //#include <windows.h>
00050 //#undef STRICT
00051 #include <winsock2.h>
00052 #undef interface
00053 
00054 #include <stdlib.h>
00055 
00056 #include <process.h>
00057 
00061 struct DBusBabysitter
00062   {
00063     int refcount;
00064 
00065     HANDLE start_sync_event;
00066 #ifdef DBUS_BUILD_TESTS
00067 
00068     HANDLE end_sync_event;
00069 #endif
00070 
00071     char *executable;
00072     DBusSpawnChildSetupFunc child_setup;
00073     void *user_data;
00074 
00075     int argc;
00076     char **argv;
00077     char **envp;
00078 
00079     HANDLE child_handle;
00080     int socket_to_babysitter;   /* Connection to the babysitter thread */
00081     int socket_to_main;
00082 
00083     DBusWatchList *watches;
00084     DBusWatch *sitter_watch;
00085 
00086     dbus_bool_t have_spawn_errno;
00087     int spawn_errno;
00088     dbus_bool_t have_child_status;
00089     int child_status;
00090   };
00091 
00092 static DBusBabysitter*
00093 _dbus_babysitter_new (void)
00094 {
00095   DBusBabysitter *sitter;
00096 
00097   sitter = dbus_new0 (DBusBabysitter, 1);
00098   if (sitter == NULL)
00099     return NULL;
00100 
00101   sitter->refcount = 1;
00102 
00103   sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
00104   if (sitter->start_sync_event == NULL)
00105     {
00106       _dbus_babysitter_unref (sitter);
00107       return NULL;
00108     }
00109 
00110 #ifdef DBUS_BUILD_TESTS
00111   sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
00112   if (sitter->end_sync_event == NULL)
00113     {
00114       _dbus_babysitter_unref (sitter);
00115       return NULL;
00116     }
00117 #endif
00118 
00119   sitter->child_handle = NULL;
00120 
00121   sitter->socket_to_babysitter = sitter->socket_to_main = -1;
00122 
00123   sitter->argc = 0;
00124   sitter->argv = NULL;
00125   sitter->envp = NULL;
00126 
00127   sitter->watches = _dbus_watch_list_new ();
00128   if (sitter->watches == NULL)
00129     {
00130       _dbus_babysitter_unref (sitter);
00131       return NULL;
00132     }
00133 
00134   sitter->have_spawn_errno = FALSE;
00135   sitter->have_child_status = FALSE;
00136 
00137   return sitter;
00138 }
00139 
00146 DBusBabysitter *
00147 _dbus_babysitter_ref (DBusBabysitter *sitter)
00148 {
00149   PING();
00150   _dbus_assert (sitter != NULL);
00151   _dbus_assert (sitter->refcount > 0);
00152 
00153   sitter->refcount += 1;
00154 
00155   return sitter;
00156 }
00157 
00163 void
00164 _dbus_babysitter_unref (DBusBabysitter *sitter)
00165 {
00166   int i;
00167 
00168   PING();
00169   _dbus_assert (sitter != NULL);
00170   _dbus_assert (sitter->refcount > 0);
00171 
00172   sitter->refcount -= 1;
00173 
00174   if (sitter->refcount == 0)
00175     {
00176       if (sitter->socket_to_babysitter != -1)
00177         {
00178           _dbus_close_socket (sitter->socket_to_babysitter, NULL);
00179           sitter->socket_to_babysitter = -1;
00180         }
00181 
00182       if (sitter->socket_to_main != -1)
00183         {
00184           _dbus_close_socket (sitter->socket_to_main, NULL);
00185           sitter->socket_to_main = -1;
00186         }
00187 
00188       PING();
00189       if (sitter->argv != NULL)
00190         {
00191           for (i = 0; i < sitter->argc; i++)
00192             if (sitter->argv[i] != NULL)
00193               {
00194                 dbus_free (sitter->argv[i]);
00195                 sitter->argv[i] = NULL;
00196               }
00197           dbus_free (sitter->argv);
00198           sitter->argv = NULL;
00199         }
00200 
00201       if (sitter->envp != NULL)
00202         {
00203           char **e = sitter->envp;
00204 
00205           while (*e)
00206             dbus_free (*e++);
00207           dbus_free (sitter->envp);
00208           sitter->envp = NULL;
00209         }
00210 
00211       if (sitter->child_handle != NULL)
00212         {
00213           CloseHandle (sitter->child_handle);
00214           sitter->child_handle = NULL;
00215         }
00216 
00217       if (sitter->sitter_watch)
00218         {
00219           _dbus_watch_invalidate (sitter->sitter_watch);
00220           _dbus_watch_unref (sitter->sitter_watch);
00221           sitter->sitter_watch = NULL;
00222         }
00223 
00224       if (sitter->watches)
00225         _dbus_watch_list_free (sitter->watches);
00226 
00227       if (sitter->start_sync_event != NULL)
00228         {
00229           PING();
00230           CloseHandle (sitter->start_sync_event);
00231           sitter->end_sync_event = NULL;
00232         }
00233 
00234 #ifdef DBUS_BUILD_TESTS
00235       if (sitter->end_sync_event != NULL)
00236         {
00237           CloseHandle (sitter->end_sync_event);
00238           sitter->end_sync_event = NULL;
00239         }
00240 #endif
00241 
00242       dbus_free (sitter->executable);
00243 
00244       dbus_free (sitter);
00245     }
00246 }
00247 
00248 void
00249 _dbus_babysitter_kill_child (DBusBabysitter *sitter)
00250 {
00251   PING();
00252   if (sitter->child_handle == NULL)
00253     return; /* child is already dead, or we're so hosed we'll never recover */
00254 
00255   PING();
00256   TerminateProcess (sitter->child_handle, 12345);
00257 }
00258 
00264 dbus_bool_t
00265 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
00266 {
00267   PING();
00268   return (sitter->child_handle == NULL);
00269 }
00270 
00280 void
00281 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
00282                                        DBusError      *error)
00283 {
00284   PING();
00285   if (!_dbus_babysitter_get_child_exited (sitter))
00286     return;
00287 
00288   PING();
00289   if (sitter->have_spawn_errno)
00290     {
00291       dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
00292                       "Failed to execute program %s: %s",
00293                       sitter->executable, _dbus_strerror (sitter->spawn_errno));
00294     }
00295   else if (sitter->have_child_status)
00296     {
00297       PING();
00298       dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
00299                       "Process %s exited with status %d",
00300                       sitter->executable, sitter->child_status);
00301     }
00302   else
00303     {
00304       PING();
00305       dbus_set_error (error, DBUS_ERROR_FAILED,
00306                       "Process %s exited, status unknown",
00307                       sitter->executable);
00308     }
00309   PING();
00310 }
00311 
00312 dbus_bool_t
00313 _dbus_babysitter_set_watch_functions (DBusBabysitter            *sitter,
00314                                       DBusAddWatchFunction       add_function,
00315                                       DBusRemoveWatchFunction    remove_function,
00316                                       DBusWatchToggledFunction   toggled_function,
00317                                       void                      *data,
00318                                       DBusFreeFunction           free_data_function)
00319 {
00320   PING();
00321   return _dbus_watch_list_set_functions (sitter->watches,
00322                                          add_function,
00323                                          remove_function,
00324                                          toggled_function,
00325                                          data,
00326                                          free_data_function);
00327 }
00328 
00329 static dbus_bool_t
00330 handle_watch (DBusWatch       *watch,
00331               unsigned int     condition,
00332               void            *data)
00333 {
00334   DBusBabysitter *sitter = data;
00335 
00336   /* On Unix dbus-spawn uses a babysitter *process*, thus it has to
00337    * actually send the exit statuses, error codes and whatnot through
00338    * sockets and/or pipes. On Win32, the babysitter is jus a thread,
00339    * so it can set the status fields directly in the babysitter struct
00340    * just fine. The socket pipe is used just so we can watch it with
00341    * select(), as soon as anything is written to it we know that the
00342    * babysitter thread has recorded the status in the babysitter
00343    * struct.
00344    */
00345 
00346   PING();
00347   _dbus_close_socket (sitter->socket_to_babysitter, NULL);
00348   PING();
00349   sitter->socket_to_babysitter = -1;
00350 
00351   return TRUE;
00352 }
00353 
00354 /* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */
00355 static int
00356 protect_argv (char  **argv,
00357               char ***new_argv)
00358 {
00359   int i;
00360   int argc = 0;
00361 
00362   while (argv[argc])
00363     ++argc;
00364   *new_argv = dbus_malloc ((argc + 1) * sizeof (char *));
00365   if (*new_argv == NULL)
00366     return -1;
00367 
00368   for (i = 0; i < argc; i++)
00369     (*new_argv)[i] = NULL;
00370 
00371   /* Quote each argv element if necessary, so that it will get
00372    * reconstructed correctly in the C runtime startup code.  Note that
00373    * the unquoting algorithm in the C runtime is really weird, and
00374    * rather different than what Unix shells do. See stdargv.c in the C
00375    * runtime sources (in the Platform SDK, in src/crt).
00376    *
00377    * Note that an new_argv[0] constructed by this function should
00378    * *not* be passed as the filename argument to a spawn* or exec*
00379    * family function. That argument should be the real file name
00380    * without any quoting.
00381    */
00382   for (i = 0; i < argc; i++)
00383     {
00384       char *p = argv[i];
00385       char *q;
00386       int len = 0;
00387       int need_dblquotes = FALSE;
00388       while (*p)
00389         {
00390           if (*p == ' ' || *p == '\t')
00391             need_dblquotes = TRUE;
00392           else if (*p == '"')
00393             len++;
00394           else if (*p == '\\')
00395             {
00396               char *pp = p;
00397               while (*pp && *pp == '\\')
00398                 pp++;
00399               if (*pp == '"')
00400                 len++;
00401             }
00402           len++;
00403           p++;
00404         }
00405 
00406       q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1);
00407 
00408       if (q == NULL)
00409         return -1;
00410 
00411 
00412       p = argv[i];
00413 
00414       if (need_dblquotes)
00415         *q++ = '"';
00416 
00417       while (*p)
00418         {
00419           if (*p == '"')
00420             *q++ = '\\';
00421           else if (*p == '\\')
00422             {
00423               char *pp = p;
00424               while (*pp && *pp == '\\')
00425                 pp++;
00426               if (*pp == '"')
00427                 *q++ = '\\';
00428             }
00429           *q++ = *p;
00430           p++;
00431         }
00432 
00433       if (need_dblquotes)
00434         *q++ = '"';
00435       *q++ = '\0';
00436       /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */
00437     }
00438   (*new_argv)[argc] = NULL;
00439 
00440   return argc;
00441 }
00442 
00443 static unsigned __stdcall
00444 babysitter (void *parameter)
00445 {
00446   DBusBabysitter *sitter = (DBusBabysitter *) parameter;
00447   int fd;
00448   PING();
00449   _dbus_babysitter_ref (sitter);
00450 
00451   if (sitter->child_setup)
00452     {
00453       PING();
00454       (*sitter->child_setup) (sitter->user_data);
00455     }
00456 
00457   _dbus_verbose ("babysitter: spawning %s\n", sitter->executable);
00458 
00459   PING();
00460   if (sitter->envp != NULL)
00461     sitter->child_handle = (HANDLE) spawnve (P_NOWAIT, sitter->executable,
00462                            (const char * const *) sitter->argv,
00463                            (const char * const *) sitter->envp);
00464   else
00465     sitter->child_handle = (HANDLE) spawnv (P_NOWAIT, sitter->executable,
00466                                             (const char * const *) sitter->argv);
00467 
00468   PING();
00469   if (sitter->child_handle == (HANDLE) -1)
00470     {
00471       sitter->child_handle = NULL;
00472       sitter->have_spawn_errno = TRUE;
00473       sitter->spawn_errno = errno;
00474     }
00475 
00476   PING();
00477   SetEvent (sitter->start_sync_event);
00478 
00479   if (sitter->child_handle != NULL)
00480     {
00481       int ret;
00482       DWORD status;
00483 
00484       PING();
00485       WaitForSingleObject (sitter->child_handle, INFINITE);
00486 
00487       PING();
00488       ret = GetExitCodeProcess (sitter->child_handle, &status);
00489 
00490       sitter->child_status = status;
00491       sitter->have_child_status = TRUE;
00492 
00493       CloseHandle (sitter->child_handle);
00494       sitter->child_handle = NULL;
00495     }
00496 
00497 #ifdef DBUS_BUILD_TESTS
00498   SetEvent (sitter->end_sync_event);
00499 #endif
00500 
00501   PING();
00502   send (sitter->socket_to_main, " ", 1, 0);
00503 
00504   _dbus_babysitter_unref (sitter);
00505 
00506   return 0;
00507 }
00508 
00509 dbus_bool_t
00510 _dbus_spawn_async_with_babysitter (DBusBabysitter           **sitter_p,
00511                                    char                     **argv,
00512                                    char                     **envp,
00513                                    DBusSpawnChildSetupFunc    child_setup,
00514                                    void                      *user_data,
00515                                    DBusError                 *error)
00516 {
00517   DBusBabysitter *sitter;
00518   HANDLE sitter_thread;
00519   int sitter_thread_id;
00520 
00521   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00522 
00523   *sitter_p = NULL;
00524 
00525   PING();
00526   sitter = _dbus_babysitter_new ();
00527   if (sitter == NULL)
00528     {
00529       _DBUS_SET_OOM (error);
00530       return FALSE;
00531     }
00532 
00533   sitter->child_setup = child_setup;
00534   sitter->user_data = user_data;
00535 
00536   sitter->executable = _dbus_strdup (argv[0]);
00537   if (sitter->executable == NULL)
00538     {
00539       _DBUS_SET_OOM (error);
00540       goto out0;
00541     }
00542 
00543   PING();
00544   if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter,
00545                                &sitter->socket_to_main,
00546                                FALSE, error))
00547     goto out0;
00548 
00549   sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter,
00550                                           DBUS_WATCH_READABLE,
00551                                           TRUE, handle_watch, sitter, NULL);
00552   PING();
00553   if (sitter->sitter_watch == NULL)
00554     {
00555       _DBUS_SET_OOM (error);
00556       goto out0;
00557     }
00558 
00559   PING();
00560   if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
00561     {
00562       _DBUS_SET_OOM (error);
00563       goto out0;
00564     }
00565 
00566   sitter->argc = protect_argv (argv, &sitter->argv);
00567   if (sitter->argc == -1)
00568     {
00569       _DBUS_SET_OOM (error);
00570       goto out0;
00571     }
00572   sitter->envp = envp;
00573 
00574   PING();
00575   sitter_thread = (HANDLE) _beginthreadex (NULL, 0, babysitter,
00576                   sitter, 0, &sitter_thread_id);
00577 
00578   if (sitter_thread == 0)
00579     {
00580       PING();
00581       dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED,
00582                             "Failed to create new thread");
00583       goto out0;
00584     }
00585   CloseHandle (sitter_thread);
00586 
00587   PING();
00588   WaitForSingleObject (sitter->start_sync_event, INFINITE);
00589 
00590   PING();
00591   if (sitter_p != NULL)
00592     *sitter_p = sitter;
00593   else
00594     _dbus_babysitter_unref (sitter);
00595 
00596   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00597 
00598   PING();
00599   return TRUE;
00600 
00601 out0:
00602   _dbus_babysitter_unref (sitter);
00603 
00604   return FALSE;
00605 }
00606 
00607 #ifdef DBUS_BUILD_TESTS
00608 
00609 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)
00610 
00611 static void
00612 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
00613 {
00614   if (sitter->child_handle == NULL)
00615     return;
00616 
00617   WaitForSingleObject (sitter->end_sync_event, INFINITE);
00618 }
00619 
00620 static dbus_bool_t
00621 check_spawn_nonexistent (void *data)
00622 {
00623   char *argv[4] = { NULL, NULL, NULL, NULL };
00624   DBusBabysitter *sitter;
00625   DBusError error;
00626 
00627   sitter = NULL;
00628 
00629   dbus_error_init (&error);
00630 
00631   /*** Test launching nonexistent binary */
00632 
00633   argv[0] = "/this/does/not/exist/32542sdgafgafdg";
00634   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00635                                          NULL, NULL,
00636                                          &error))
00637     {
00638       _dbus_babysitter_block_for_child_exit (sitter);
00639       _dbus_babysitter_set_child_exit_error (sitter, &error);
00640     }
00641 
00642   if (sitter)
00643     _dbus_babysitter_unref (sitter);
00644 
00645   if (!dbus_error_is_set (&error))
00646     {
00647       _dbus_warn ("Did not get an error launching nonexistent executable\n");
00648       return FALSE;
00649     }
00650 
00651   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00652         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
00653     {
00654       _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
00655                   error.name, error.message);
00656       dbus_error_free (&error);
00657       return FALSE;
00658     }
00659 
00660   dbus_error_free (&error);
00661 
00662   return TRUE;
00663 }
00664 
00665 static dbus_bool_t
00666 check_spawn_segfault (void *data)
00667 {
00668   char *argv[4] = { NULL, NULL, NULL, NULL };
00669   DBusBabysitter *sitter;
00670   DBusError error;
00671 
00672   sitter = NULL;
00673 
00674   dbus_error_init (&error);
00675 
00676   /*** Test launching segfault binary */
00677 
00678   argv[0] = TEST_SEGFAULT_BINARY;
00679   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00680                                          NULL, NULL,
00681                                          &error))
00682     {
00683       _dbus_babysitter_block_for_child_exit (sitter);
00684       _dbus_babysitter_set_child_exit_error (sitter, &error);
00685     }
00686 
00687   if (sitter)
00688     _dbus_babysitter_unref (sitter);
00689 
00690   if (!dbus_error_is_set (&error))
00691     {
00692       _dbus_warn ("Did not get an error launching segfaulting binary\n");
00693       return FALSE;
00694     }
00695 
00696   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00697         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
00698     {
00699       _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
00700                   error.name, error.message);
00701       dbus_error_free (&error);
00702       return FALSE;
00703     }
00704 
00705   dbus_error_free (&error);
00706 
00707   return TRUE;
00708 }
00709 
00710 static dbus_bool_t
00711 check_spawn_exit (void *data)
00712 {
00713   char *argv[4] = { NULL, NULL, NULL, NULL };
00714   DBusBabysitter *sitter;
00715   DBusError error;
00716 
00717   sitter = NULL;
00718 
00719   dbus_error_init (&error);
00720 
00721   /*** Test launching exit failure binary */
00722 
00723   argv[0] = TEST_EXIT_BINARY;
00724   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00725                                          NULL, NULL,
00726                                          &error))
00727     {
00728       _dbus_babysitter_block_for_child_exit (sitter);
00729       _dbus_babysitter_set_child_exit_error (sitter, &error);
00730     }
00731 
00732   if (sitter)
00733     _dbus_babysitter_unref (sitter);
00734 
00735   if (!dbus_error_is_set (&error))
00736     {
00737       _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
00738       return FALSE;
00739     }
00740 
00741   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00742         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
00743     {
00744       _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
00745                   error.name, error.message);
00746       dbus_error_free (&error);
00747       return FALSE;
00748     }
00749 
00750   dbus_error_free (&error);
00751 
00752   return TRUE;
00753 }
00754 
00755 static dbus_bool_t
00756 check_spawn_and_kill (void *data)
00757 {
00758   char *argv[4] = { NULL, NULL, NULL, NULL };
00759   DBusBabysitter *sitter;
00760   DBusError error;
00761 
00762   sitter = NULL;
00763 
00764   dbus_error_init (&error);
00765 
00766   /*** Test launching sleeping binary then killing it */
00767 
00768   argv[0] = TEST_SLEEP_FOREVER_BINARY;
00769   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00770                                          NULL, NULL,
00771                                          &error))
00772     {
00773       _dbus_babysitter_kill_child (sitter);
00774 
00775       _dbus_babysitter_block_for_child_exit (sitter);
00776 
00777       _dbus_babysitter_set_child_exit_error (sitter, &error);
00778     }
00779 
00780   if (sitter)
00781     _dbus_babysitter_unref (sitter);
00782 
00783   if (!dbus_error_is_set (&error))
00784     {
00785       _dbus_warn ("Did not get an error after killing spawned binary\n");
00786       return FALSE;
00787     }
00788 
00789   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00790         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
00791     {
00792       _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
00793                   error.name, error.message);
00794       dbus_error_free (&error);
00795       return FALSE;
00796     }
00797 
00798   dbus_error_free (&error);
00799 
00800   return TRUE;
00801 }
00802 
00803 dbus_bool_t
00804 _dbus_spawn_test (const char *test_data_dir)
00805 {
00806   if (!_dbus_test_oom_handling ("spawn_nonexistent",
00807                                 check_spawn_nonexistent,
00808                                 NULL))
00809     return FALSE;
00810 
00811   /* Don't run the obnoxious segfault test by default,
00812    * it's a pain to have to click all those error boxes.
00813    */
00814   if (getenv ("DO_SEGFAULT_TEST"))
00815     if (!_dbus_test_oom_handling ("spawn_segfault",
00816                                   check_spawn_segfault,
00817                                   NULL))
00818       return FALSE;
00819 
00820   if (!_dbus_test_oom_handling ("spawn_exit",
00821                                 check_spawn_exit,
00822                                 NULL))
00823     return FALSE;
00824 
00825   if (!_dbus_test_oom_handling ("spawn_and_kill",
00826                                 check_spawn_and_kill,
00827                                 NULL))
00828     return FALSE;
00829 
00830   return TRUE;
00831 }
00832 #endif

Generated on Wed Aug 29 12:15:04 2007 for D-Bus by  doxygen 1.5.2