• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List

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 
00013 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00014 /* dbus-spawn-win32.c Wrapper around g_spawn
00015  * 
00016  * Copyright (C) 2002, 2003, 2004  Red Hat, Inc.
00017  * Copyright (C) 2003 CodeFactory AB
00018  * Copyright (C) 2005 Novell, Inc.
00019  *
00020  * Licensed under the Academic Free License version 2.1
00021  * 
00022  * This program is free software; you can redistribute it and/or modify
00023  * it under the terms of the GNU General Public License as published by
00024  * the Free Software Foundation; either version 2 of the License, or
00025  * (at your option) any later version.
00026  *
00027  * This program is distributed in the hope that it will be useful,
00028  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00029  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00030  * GNU General Public License for more details.
00031  * 
00032  * You should have received a copy of the GNU General Public License
00033  * along with this program; if not, write to the Free Software
00034  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00035  *
00036  */
00037 #include "dbus-spawn.h"
00038 #include "dbus-sysdeps.h"
00039 #include "dbus-sysdeps-win.h"
00040 #include "dbus-internals.h"
00041 #include "dbus-test.h"
00042 #include "dbus-protocol.h"
00043 
00044 #define WIN32_LEAN_AND_MEAN
00045 //#define STRICT
00046 //#include <windows.h>
00047 //#undef STRICT
00048 #include <winsock2.h>
00049 #undef interface
00050 
00051 #include <stdlib.h>
00052 
00053 #ifndef DBUS_WINCE
00054 #include <process.h>
00055 #endif
00056 
00060 struct DBusBabysitter
00061   {
00062     int refcount;
00063 
00064     HANDLE start_sync_event;
00065 #ifdef DBUS_BUILD_TESTS
00066 
00067     HANDLE end_sync_event;
00068 #endif
00069 
00070     char *executable;
00071     DBusSpawnChildSetupFunc child_setup;
00072     void *user_data;
00073 
00074     int argc;
00075     char **argv;
00076     char **envp;
00077 
00078     HANDLE child_handle;
00079     int socket_to_babysitter;   /* Connection to the babysitter thread */
00080     int socket_to_main;
00081 
00082     DBusWatchList *watches;
00083     DBusWatch *sitter_watch;
00084     DBusBabysitterFinishedFunc finished_cb;
00085     void *finished_data;
00086 
00087     dbus_bool_t have_spawn_errno;
00088     int spawn_errno;
00089     dbus_bool_t have_child_status;
00090     int child_status;
00091   };
00092 
00093 static DBusBabysitter*
00094 _dbus_babysitter_new (void)
00095 {
00096   DBusBabysitter *sitter;
00097 
00098   sitter = dbus_new0 (DBusBabysitter, 1);
00099   if (sitter == NULL)
00100     return NULL;
00101 
00102   sitter->refcount = 1;
00103 
00104   sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
00105   if (sitter->start_sync_event == NULL)
00106     {
00107       _dbus_babysitter_unref (sitter);
00108       return NULL;
00109     }
00110 
00111 #ifdef DBUS_BUILD_TESTS
00112   sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
00113   if (sitter->end_sync_event == NULL)
00114     {
00115       _dbus_babysitter_unref (sitter);
00116       return NULL;
00117     }
00118 #endif
00119 
00120   sitter->child_handle = NULL;
00121 
00122   sitter->socket_to_babysitter = sitter->socket_to_main = -1;
00123 
00124   sitter->argc = 0;
00125   sitter->argv = NULL;
00126   sitter->envp = NULL;
00127 
00128   sitter->watches = _dbus_watch_list_new ();
00129   if (sitter->watches == NULL)
00130     {
00131       _dbus_babysitter_unref (sitter);
00132       return NULL;
00133     }
00134 
00135   sitter->have_spawn_errno = FALSE;
00136   sitter->have_child_status = FALSE;
00137 
00138   return sitter;
00139 }
00140 
00147 DBusBabysitter *
00148 _dbus_babysitter_ref (DBusBabysitter *sitter)
00149 {
00150   PING();
00151   _dbus_assert (sitter != NULL);
00152   _dbus_assert (sitter->refcount > 0);
00153 
00154   sitter->refcount += 1;
00155 
00156   return sitter;
00157 }
00158 
00159 static void
00160 close_socket_to_babysitter (DBusBabysitter *sitter)
00161 {
00162   _dbus_verbose ("Closing babysitter\n");
00163 
00164   if (sitter->sitter_watch != NULL)
00165     {
00166       _dbus_assert (sitter->watches != NULL);
00167       _dbus_watch_list_remove_watch (sitter->watches,  sitter->sitter_watch);
00168       _dbus_watch_invalidate (sitter->sitter_watch);
00169       _dbus_watch_unref (sitter->sitter_watch);
00170       sitter->sitter_watch = NULL;
00171     }
00172 
00173   if (sitter->socket_to_babysitter != -1)
00174     {
00175       _dbus_close_socket (sitter->socket_to_babysitter, NULL);
00176       sitter->socket_to_babysitter = -1;
00177     }
00178 }
00179 
00185 void
00186 _dbus_babysitter_unref (DBusBabysitter *sitter)
00187 {
00188   int i;
00189 
00190   PING();
00191   _dbus_assert (sitter != NULL);
00192   _dbus_assert (sitter->refcount > 0);
00193 
00194   sitter->refcount -= 1;
00195 
00196   if (sitter->refcount == 0)
00197     {
00198       close_socket_to_babysitter (sitter);
00199 
00200       if (sitter->socket_to_main != -1)
00201         {
00202           _dbus_close_socket (sitter->socket_to_main, NULL);
00203           sitter->socket_to_main = -1;
00204         }
00205 
00206       PING();
00207       if (sitter->argv != NULL)
00208         {
00209           for (i = 0; i < sitter->argc; i++)
00210             if (sitter->argv[i] != NULL)
00211               {
00212                 dbus_free (sitter->argv[i]);
00213                 sitter->argv[i] = NULL;
00214               }
00215           dbus_free (sitter->argv);
00216           sitter->argv = NULL;
00217         }
00218 
00219       if (sitter->envp != NULL)
00220         {
00221           char **e = sitter->envp;
00222 
00223           while (*e)
00224             dbus_free (*e++);
00225           dbus_free (sitter->envp);
00226           sitter->envp = NULL;
00227         }
00228 
00229       if (sitter->child_handle != NULL)
00230         {
00231           CloseHandle (sitter->child_handle);
00232           sitter->child_handle = NULL;
00233         }
00234 
00235       if (sitter->sitter_watch)
00236         {
00237           _dbus_watch_invalidate (sitter->sitter_watch);
00238           _dbus_watch_unref (sitter->sitter_watch);
00239           sitter->sitter_watch = NULL;
00240         }
00241 
00242       if (sitter->watches)
00243         _dbus_watch_list_free (sitter->watches);
00244 
00245       if (sitter->start_sync_event != NULL)
00246         {
00247           PING();
00248           CloseHandle (sitter->start_sync_event);
00249           sitter->start_sync_event = NULL;
00250         }
00251 
00252 #ifdef DBUS_BUILD_TESTS
00253       if (sitter->end_sync_event != NULL)
00254         {
00255           CloseHandle (sitter->end_sync_event);
00256           sitter->end_sync_event = NULL;
00257         }
00258 #endif
00259 
00260       dbus_free (sitter->executable);
00261 
00262       dbus_free (sitter);
00263     }
00264 }
00265 
00266 void
00267 _dbus_babysitter_kill_child (DBusBabysitter *sitter)
00268 {
00269   PING();
00270   if (sitter->child_handle == NULL)
00271     return; /* child is already dead, or we're so hosed we'll never recover */
00272 
00273   PING();
00274   TerminateProcess (sitter->child_handle, 12345);
00275 }
00276 
00282 dbus_bool_t
00283 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
00284 {
00285   PING();
00286   return (sitter->child_handle == NULL);
00287 }
00288 
00301 dbus_bool_t
00302 _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter,
00303                                         int            *status)
00304 {
00305   if (!_dbus_babysitter_get_child_exited (sitter))
00306     _dbus_assert_not_reached ("Child has not exited");
00307 
00308   if (!sitter->have_child_status ||
00309       sitter->child_status == STILL_ACTIVE)
00310     return FALSE;
00311 
00312   *status = sitter->child_status;
00313   return TRUE;
00314 }
00315 
00325 void
00326 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
00327                                        DBusError      *error)
00328 {
00329   PING();
00330   if (!_dbus_babysitter_get_child_exited (sitter))
00331     return;
00332 
00333   PING();
00334   if (sitter->have_spawn_errno)
00335     {
00336       char *emsg = _dbus_win_error_string (sitter->spawn_errno);
00337       dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
00338                       "Failed to execute program %s: %s",
00339                       sitter->executable, emsg);
00340       _dbus_win_free_error_string (emsg);
00341     }
00342   else if (sitter->have_child_status)
00343     {
00344       PING();
00345       dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
00346                       "Process %s exited with status %d",
00347                       sitter->executable, sitter->child_status);
00348     }
00349   else
00350     {
00351       PING();
00352       dbus_set_error (error, DBUS_ERROR_FAILED,
00353                       "Process %s exited, status unknown",
00354                       sitter->executable);
00355     }
00356   PING();
00357 }
00358 
00359 dbus_bool_t
00360 _dbus_babysitter_set_watch_functions (DBusBabysitter            *sitter,
00361                                       DBusAddWatchFunction       add_function,
00362                                       DBusRemoveWatchFunction    remove_function,
00363                                       DBusWatchToggledFunction   toggled_function,
00364                                       void                      *data,
00365                                       DBusFreeFunction           free_data_function)
00366 {
00367   PING();
00368   return _dbus_watch_list_set_functions (sitter->watches,
00369                                          add_function,
00370                                          remove_function,
00371                                          toggled_function,
00372                                          data,
00373                                          free_data_function);
00374 }
00375 
00376 static dbus_bool_t
00377 handle_watch (DBusWatch       *watch,
00378               unsigned int     condition,
00379               void            *data)
00380 {
00381   DBusBabysitter *sitter = data;
00382 
00383   /* On Unix dbus-spawn uses a babysitter *process*, thus it has to
00384    * actually send the exit statuses, error codes and whatnot through
00385    * sockets and/or pipes. On Win32, the babysitter is jus a thread,
00386    * so it can set the status fields directly in the babysitter struct
00387    * just fine. The socket pipe is used just so we can watch it with
00388    * select(), as soon as anything is written to it we know that the
00389    * babysitter thread has recorded the status in the babysitter
00390    * struct.
00391    */
00392 
00393   PING();
00394   close_socket_to_babysitter (sitter);
00395   PING();
00396 
00397   if (_dbus_babysitter_get_child_exited (sitter) &&
00398       sitter->finished_cb != NULL)
00399     {
00400       sitter->finished_cb (sitter, sitter->finished_data);
00401       sitter->finished_cb = NULL;
00402     }
00403 
00404   return TRUE;
00405 }
00406 
00407 /* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */
00408 static int
00409 protect_argv (char  **argv,
00410               char ***new_argv)
00411 {
00412   int i;
00413   int argc = 0;
00414 
00415   while (argv[argc])
00416     ++argc;
00417   *new_argv = dbus_malloc ((argc + 1) * sizeof (char *));
00418   if (*new_argv == NULL)
00419     return -1;
00420 
00421   for (i = 0; i < argc; i++)
00422     (*new_argv)[i] = NULL;
00423 
00424   /* Quote each argv element if necessary, so that it will get
00425    * reconstructed correctly in the C runtime startup code.  Note that
00426    * the unquoting algorithm in the C runtime is really weird, and
00427    * rather different than what Unix shells do. See stdargv.c in the C
00428    * runtime sources (in the Platform SDK, in src/crt).
00429    *
00430    * Note that an new_argv[0] constructed by this function should
00431    * *not* be passed as the filename argument to a spawn* or exec*
00432    * family function. That argument should be the real file name
00433    * without any quoting.
00434    */
00435   for (i = 0; i < argc; i++)
00436     {
00437       char *p = argv[i];
00438       char *q;
00439       int len = 0;
00440       int need_dblquotes = FALSE;
00441       while (*p)
00442         {
00443           if (*p == ' ' || *p == '\t')
00444             need_dblquotes = TRUE;
00445           else if (*p == '"')
00446             len++;
00447           else if (*p == '\\')
00448             {
00449               char *pp = p;
00450               while (*pp && *pp == '\\')
00451                 pp++;
00452               if (*pp == '"')
00453                 len++;
00454             }
00455           len++;
00456           p++;
00457         }
00458 
00459       q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1);
00460 
00461       if (q == NULL)
00462         return -1;
00463 
00464 
00465       p = argv[i];
00466 
00467       if (need_dblquotes)
00468         *q++ = '"';
00469 
00470       while (*p)
00471         {
00472           if (*p == '"')
00473             *q++ = '\\';
00474           else if (*p == '\\')
00475             {
00476               char *pp = p;
00477               while (*pp && *pp == '\\')
00478                 pp++;
00479               if (*pp == '"')
00480                 *q++ = '\\';
00481             }
00482           *q++ = *p;
00483           p++;
00484         }
00485 
00486       if (need_dblquotes)
00487         *q++ = '"';
00488       *q++ = '\0';
00489       /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */
00490     }
00491   (*new_argv)[argc] = NULL;
00492 
00493   return argc;
00494 }
00495 
00496 
00497 /* From GPGME, relicensed by g10 Code GmbH.  */
00498 static char *
00499 compose_string (char **strings, char separator)
00500 {
00501   int i;
00502   int n = 0;
00503   char *buf;
00504   char *p;
00505   const char *ptr;
00506   
00507   if (!strings || !strings[0])
00508     return 0;
00509   for (i = 0; strings[i]; i++)
00510     n += strlen (strings[i]) + 1;
00511   n++;
00512 
00513   buf = p = malloc (n);
00514   if (!buf)
00515     return NULL;
00516   for (i = 0; strings[i]; i++)
00517     {
00518       strcpy (p, strings[i]);
00519       p += strlen (strings[i]);
00520       *(p++) = separator;
00521     }
00522   p--;
00523   *(p++) = '\0';
00524   *p = '\0';
00525 
00526   return buf;
00527 }
00528 
00529 static char *
00530 build_commandline (char **argv)
00531 {
00532   return compose_string (argv, ' ');
00533 }
00534 
00535 static char *
00536 build_env_string (char** envp)
00537 {
00538   return compose_string (envp, '\0');
00539 }
00540 
00541 static HANDLE
00542 spawn_program (char* name, char** argv, char** envp)
00543 {
00544   PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
00545   STARTUPINFOA si;
00546   char *arg_string, *env_string;
00547   BOOL result;
00548 
00549 #ifdef DBUS_WINCE
00550   if (argv && argv[0])
00551     arg_string = build_commandline (argv + 1);
00552   else
00553     arg_string = NULL;
00554 #else
00555   arg_string = build_commandline (argv);
00556 #endif
00557   if (!arg_string)
00558     return INVALID_HANDLE_VALUE;
00559 
00560   env_string = build_env_string(envp);
00561 
00562   memset (&si, 0, sizeof (si));
00563   si.cb = sizeof (si);
00564 #ifdef DBUS_WINCE
00565   result = CreateProcessA (name, arg_string, NULL, NULL, FALSE, 0,
00566 #else
00567   result = CreateProcessA (NULL, arg_string, NULL, NULL, FALSE, 0,
00568 #endif
00569                            (LPVOID)env_string, NULL, &si, &pi);
00570   free (arg_string);
00571   if (env_string)
00572     free (env_string);
00573 
00574   if (!result)
00575     return INVALID_HANDLE_VALUE;
00576 
00577   CloseHandle (pi.hThread);
00578   return pi.hProcess;
00579 }
00580 
00581 
00582 static DWORD __stdcall
00583 babysitter (void *parameter)
00584 {
00585   DBusBabysitter *sitter = (DBusBabysitter *) parameter;
00586   int fd;
00587   PING();
00588   _dbus_babysitter_ref (sitter);
00589 
00590   if (sitter->child_setup)
00591     {
00592       PING();
00593       (*sitter->child_setup) (sitter->user_data);
00594     }
00595 
00596   _dbus_verbose ("babysitter: spawning %s\n", sitter->executable);
00597 
00598   PING();
00599   sitter->child_handle = spawn_program (sitter->executable,
00600                                         sitter->argv, sitter->envp);
00601 
00602   PING();
00603   if (sitter->child_handle == (HANDLE) -1)
00604     {
00605       sitter->child_handle = NULL;
00606       sitter->have_spawn_errno = TRUE;
00607       sitter->spawn_errno = GetLastError();
00608     }
00609   
00610   PING();
00611   SetEvent (sitter->start_sync_event);
00612 
00613   if (sitter->child_handle != NULL)
00614     {
00615       int ret;
00616       DWORD status;
00617 
00618       PING();
00619       WaitForSingleObject (sitter->child_handle, INFINITE);
00620 
00621       PING();
00622       ret = GetExitCodeProcess (sitter->child_handle, &status);
00623 
00624       sitter->child_status = status;
00625       sitter->have_child_status = TRUE;
00626 
00627       CloseHandle (sitter->child_handle);
00628       sitter->child_handle = NULL;
00629     }
00630 
00631 #ifdef DBUS_BUILD_TESTS
00632   SetEvent (sitter->end_sync_event);
00633 #endif
00634 
00635   PING();
00636   send (sitter->socket_to_main, " ", 1, 0);
00637 
00638   _dbus_babysitter_unref (sitter);
00639 
00640   return 0;
00641 }
00642 
00643 dbus_bool_t
00644 _dbus_spawn_async_with_babysitter (DBusBabysitter           **sitter_p,
00645                                    char                     **argv,
00646                                    char                     **envp,
00647                                    DBusSpawnChildSetupFunc    child_setup,
00648                                    void                      *user_data,
00649                                    DBusError                 *error)
00650 {
00651   DBusBabysitter *sitter;
00652   HANDLE sitter_thread;
00653   DWORD sitter_thread_id;
00654   
00655   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00656 
00657   *sitter_p = NULL;
00658 
00659   PING();
00660   sitter = _dbus_babysitter_new ();
00661   if (sitter == NULL)
00662     {
00663       _DBUS_SET_OOM (error);
00664       return FALSE;
00665     }
00666 
00667   sitter->child_setup = child_setup;
00668   sitter->user_data = user_data;
00669 
00670   sitter->executable = _dbus_strdup (argv[0]);
00671   if (sitter->executable == NULL)
00672     {
00673       _DBUS_SET_OOM (error);
00674       goto out0;
00675     }
00676 
00677   PING();
00678   if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter,
00679                                &sitter->socket_to_main,
00680                                FALSE, error))
00681     goto out0;
00682 
00683   sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter,
00684                                           DBUS_WATCH_READABLE,
00685                                           TRUE, handle_watch, sitter, NULL);
00686   PING();
00687   if (sitter->sitter_watch == NULL)
00688     {
00689       _DBUS_SET_OOM (error);
00690       goto out0;
00691     }
00692 
00693   PING();
00694   if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
00695     {
00696       /* we need to free it early so the destructor won't try to remove it
00697        * without it having been added, which DBusLoop doesn't allow */
00698       _dbus_watch_invalidate (sitter->sitter_watch);
00699       _dbus_watch_unref (sitter->sitter_watch);
00700       sitter->sitter_watch = NULL;
00701 
00702       _DBUS_SET_OOM (error);
00703       goto out0;
00704     }
00705 
00706   sitter->argc = protect_argv (argv, &sitter->argv);
00707   if (sitter->argc == -1)
00708     {
00709       _DBUS_SET_OOM (error);
00710       goto out0;
00711     }
00712   sitter->envp = envp;
00713 
00714   PING();
00715   sitter_thread = (HANDLE) CreateThread (NULL, 0, babysitter,
00716                   sitter, 0, &sitter_thread_id);
00717 
00718   if (sitter_thread == 0)
00719     {
00720       PING();
00721       dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED,
00722                             "Failed to create new thread");
00723       goto out0;
00724     }
00725   CloseHandle (sitter_thread);
00726 
00727   PING();
00728   WaitForSingleObject (sitter->start_sync_event, INFINITE);
00729 
00730   PING();
00731   if (sitter_p != NULL)
00732     *sitter_p = sitter;
00733   else
00734     _dbus_babysitter_unref (sitter);
00735 
00736   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00737 
00738   PING();
00739   return TRUE;
00740 
00741 out0:
00742   _dbus_babysitter_unref (sitter);
00743 
00744   return FALSE;
00745 }
00746 
00747 void
00748 _dbus_babysitter_set_result_function  (DBusBabysitter             *sitter,
00749                                        DBusBabysitterFinishedFunc  finished,
00750                                        void                       *user_data)
00751 {
00752   sitter->finished_cb = finished;
00753   sitter->finished_data = user_data;
00754 }
00755 
00756 #ifdef DBUS_BUILD_TESTS
00757 
00758 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)
00759 
00760 static void
00761 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
00762 {
00763   if (sitter->child_handle == NULL)
00764     return;
00765 
00766   WaitForSingleObject (sitter->end_sync_event, INFINITE);
00767 }
00768 
00769 static dbus_bool_t
00770 check_spawn_nonexistent (void *data)
00771 {
00772   char *argv[4] = { NULL, NULL, NULL, NULL };
00773   DBusBabysitter *sitter;
00774   DBusError error;
00775 
00776   sitter = NULL;
00777 
00778   dbus_error_init (&error);
00779 
00780   /*** Test launching nonexistent binary */
00781 
00782   argv[0] = "/this/does/not/exist/32542sdgafgafdg";
00783   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00784                                          NULL, NULL,
00785                                          &error))
00786     {
00787       _dbus_babysitter_block_for_child_exit (sitter);
00788       _dbus_babysitter_set_child_exit_error (sitter, &error);
00789     }
00790 
00791   if (sitter)
00792     _dbus_babysitter_unref (sitter);
00793 
00794   if (!dbus_error_is_set (&error))
00795     {
00796       _dbus_warn ("Did not get an error launching nonexistent executable\n");
00797       return FALSE;
00798     }
00799 
00800   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00801         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
00802     {
00803       _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
00804                   error.name, error.message);
00805       dbus_error_free (&error);
00806       return FALSE;
00807     }
00808 
00809   dbus_error_free (&error);
00810 
00811   return TRUE;
00812 }
00813 
00814 static dbus_bool_t
00815 check_spawn_segfault (void *data)
00816 {
00817   char *argv[4] = { NULL, NULL, NULL, NULL };
00818   DBusBabysitter *sitter;
00819   DBusError error;
00820 
00821   sitter = NULL;
00822 
00823   dbus_error_init (&error);
00824 
00825   /*** Test launching segfault binary */
00826 
00827   argv[0] = TEST_SEGFAULT_BINARY;
00828   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00829                                          NULL, NULL,
00830                                          &error))
00831     {
00832       _dbus_babysitter_block_for_child_exit (sitter);
00833       _dbus_babysitter_set_child_exit_error (sitter, &error);
00834     }
00835 
00836   if (sitter)
00837     _dbus_babysitter_unref (sitter);
00838 
00839   if (!dbus_error_is_set (&error))
00840     {
00841       _dbus_warn ("Did not get an error launching segfaulting binary\n");
00842       return FALSE;
00843     }
00844 
00845   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00846         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
00847     {
00848       _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
00849                   error.name, error.message);
00850       dbus_error_free (&error);
00851       return FALSE;
00852     }
00853 
00854   dbus_error_free (&error);
00855 
00856   return TRUE;
00857 }
00858 
00859 static dbus_bool_t
00860 check_spawn_exit (void *data)
00861 {
00862   char *argv[4] = { NULL, NULL, NULL, NULL };
00863   DBusBabysitter *sitter;
00864   DBusError error;
00865 
00866   sitter = NULL;
00867 
00868   dbus_error_init (&error);
00869 
00870   /*** Test launching exit failure binary */
00871 
00872   argv[0] = TEST_EXIT_BINARY;
00873   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00874                                          NULL, NULL,
00875                                          &error))
00876     {
00877       _dbus_babysitter_block_for_child_exit (sitter);
00878       _dbus_babysitter_set_child_exit_error (sitter, &error);
00879     }
00880 
00881   if (sitter)
00882     _dbus_babysitter_unref (sitter);
00883 
00884   if (!dbus_error_is_set (&error))
00885     {
00886       _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
00887       return FALSE;
00888     }
00889 
00890   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00891         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
00892     {
00893       _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
00894                   error.name, error.message);
00895       dbus_error_free (&error);
00896       return FALSE;
00897     }
00898 
00899   dbus_error_free (&error);
00900 
00901   return TRUE;
00902 }
00903 
00904 static dbus_bool_t
00905 check_spawn_and_kill (void *data)
00906 {
00907   char *argv[4] = { NULL, NULL, NULL, NULL };
00908   DBusBabysitter *sitter;
00909   DBusError error;
00910 
00911   sitter = NULL;
00912 
00913   dbus_error_init (&error);
00914 
00915   /*** Test launching sleeping binary then killing it */
00916 
00917   argv[0] = TEST_SLEEP_FOREVER_BINARY;
00918   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00919                                          NULL, NULL,
00920                                          &error))
00921     {
00922       _dbus_babysitter_kill_child (sitter);
00923 
00924       _dbus_babysitter_block_for_child_exit (sitter);
00925 
00926       _dbus_babysitter_set_child_exit_error (sitter, &error);
00927     }
00928 
00929   if (sitter)
00930     _dbus_babysitter_unref (sitter);
00931 
00932   if (!dbus_error_is_set (&error))
00933     {
00934       _dbus_warn ("Did not get an error after killing spawned binary\n");
00935       return FALSE;
00936     }
00937 
00938   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00939         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
00940     {
00941       _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
00942                   error.name, error.message);
00943       dbus_error_free (&error);
00944       return FALSE;
00945     }
00946 
00947   dbus_error_free (&error);
00948 
00949   return TRUE;
00950 }
00951 
00952 dbus_bool_t
00953 _dbus_spawn_test (const char *test_data_dir)
00954 {
00955   if (!_dbus_test_oom_handling ("spawn_nonexistent",
00956                                 check_spawn_nonexistent,
00957                                 NULL))
00958     return FALSE;
00959 
00960   /* Don't run the obnoxious segfault test by default,
00961    * it's a pain to have to click all those error boxes.
00962    */
00963   if (getenv ("DO_SEGFAULT_TEST"))
00964     if (!_dbus_test_oom_handling ("spawn_segfault",
00965                                   check_spawn_segfault,
00966                                   NULL))
00967       return FALSE;
00968 
00969   if (!_dbus_test_oom_handling ("spawn_exit",
00970                                 check_spawn_exit,
00971                                 NULL))
00972     return FALSE;
00973 
00974   if (!_dbus_test_oom_handling ("spawn_and_kill",
00975                                 check_spawn_and_kill,
00976                                 NULL))
00977     return FALSE;
00978 
00979   return TRUE;
00980 }
00981 #endif

Generated on Fri Jul 11 2014 20:41:52 for D-Bus by  doxygen 1.7.1