コード例 #1
0
ファイル: dbus-spawn.c プロジェクト: d-bus/dbus
static DBusBabysitter*
_dbus_babysitter_new (void)
{
  DBusBabysitter *sitter;

  sitter = dbus_new0 (DBusBabysitter, 1);
  if (sitter == NULL)
    return NULL;

  sitter->refcount = 1;

  sitter->socket_to_babysitter.fd = -1;
  sitter->error_pipe_from_child = -1;
  
  sitter->sitter_pid = -1;
  sitter->grandchild_pid = -1;

  sitter->watches = _dbus_watch_list_new ();
  if (sitter->watches == NULL)
    goto failed;
  
  return sitter;

 failed:
  _dbus_babysitter_unref (sitter);
  return NULL;
}
コード例 #2
0
ファイル: dbus-spawn-win.c プロジェクト: psunkari/spicebird
static DBusBabysitter*
_dbus_babysitter_new (void)
{
  DBusBabysitter *sitter;

  sitter = dbus_new0 (DBusBabysitter, 1);
  if (sitter == NULL)
    return NULL;

  sitter->refcount = 1;

  sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
  if (sitter->start_sync_event == NULL)
    {
      _dbus_babysitter_unref (sitter);
      return NULL;
    }

#ifdef DBUS_BUILD_TESTS
  sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
  if (sitter->end_sync_event == NULL)
    {
      _dbus_babysitter_unref (sitter);
      return NULL;
    }
#endif

  sitter->child_handle = NULL;

  sitter->socket_to_babysitter = sitter->socket_to_main = -1;

  sitter->argc = 0;
  sitter->argv = NULL;
  sitter->envp = NULL;

  sitter->watches = _dbus_watch_list_new ();
  if (sitter->watches == NULL)
    {
      _dbus_babysitter_unref (sitter);
      return NULL;
    }

  sitter->have_spawn_errno = FALSE;
  sitter->have_child_status = FALSE;

  return sitter;
}
コード例 #3
0
ファイル: dbus-spawn.c プロジェクト: 13824125580/hello-world
static dbus_bool_t
check_spawn_and_kill (void *data)
{
  char *argv[4] = { NULL, NULL, NULL, NULL };
  DBusBabysitter *sitter = NULL;
  DBusError error = DBUS_ERROR_INIT;
  DBusString argv0;

  /*** Test launching sleeping binary then killing it */

  argv[0] = get_test_exec ("test-sleep-forever", &argv0);

  if (argv[0] == NULL)
    {
      /* OOM was simulated, never mind */
      return TRUE;
    }

  if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_and_kill", argv,
                                         NULL, NULL, NULL,
                                         &error))
    {
      _dbus_babysitter_kill_child (sitter);
      
      _dbus_babysitter_block_for_child_exit (sitter);
      
      _dbus_babysitter_set_child_exit_error (sitter, &error);
    }

  _dbus_string_free (&argv0);

  if (sitter)
    _dbus_babysitter_unref (sitter);

  if (!dbus_error_is_set (&error))
    {
      _dbus_warn ("Did not get an error after killing spawned binary\n");
      return FALSE;
    }

  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
        dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
    {
      _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
                  error.name, error.message);
      dbus_error_free (&error);
      return FALSE;
    }

  dbus_error_free (&error);
  
  return TRUE;
}
コード例 #4
0
ファイル: dbus-spawn.c プロジェクト: cdaffara/symbiandump-os2
static dbus_bool_t
check_spawn_exit (void *data)
{
  char *argv[4] = { NULL, NULL, NULL, NULL };
  DBusBabysitter *sitter;
  DBusError error;
  
  sitter = NULL;
  
  dbus_error_init (&error);

  /*** Test launching exit failure binary */
  
  argv[0] = TEST_EXIT_BINARY;
  if (_dbus_spawn_async_with_babysitter (&sitter, argv,
                                         NULL, NULL,
                                         &error))
    {
    #ifdef __SYMBIAN32__
    if(sitter)
    {
    #endif
      _dbus_babysitter_block_for_child_exit (sitter);
      _dbus_babysitter_set_child_exit_error (sitter, &error);
      
    #ifdef __SYMBIAN32__
    }
    #endif
      /* no baby sitter support in Symbian */
    }

  if (sitter)
    _dbus_babysitter_unref (sitter);

  if (!dbus_error_is_set (&error))
    {
      _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
      return FALSE;
    }

  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
        dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
    {
      _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
                  error.name, error.message);
      dbus_error_free (&error);
      return FALSE;
    }

  dbus_error_free (&error);
  
  return TRUE;
}
コード例 #5
0
ファイル: dbus-spawn-win.c プロジェクト: psunkari/spicebird
static dbus_bool_t
check_spawn_and_kill (void *data)
{
  char *argv[4] = { NULL, NULL, NULL, NULL };
  DBusBabysitter *sitter;
  DBusError error;

  sitter = NULL;

  dbus_error_init (&error);

  /*** Test launching sleeping binary then killing it */

  argv[0] = TEST_SLEEP_FOREVER_BINARY;
  if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
                                         NULL, NULL,
                                         &error))
    {
      _dbus_babysitter_kill_child (sitter);

      _dbus_babysitter_block_for_child_exit (sitter);

      _dbus_babysitter_set_child_exit_error (sitter, &error);
    }

  if (sitter)
    _dbus_babysitter_unref (sitter);

  if (!dbus_error_is_set (&error))
    {
      _dbus_warn ("Did not get an error after killing spawned binary\n");
      return FALSE;
    }

  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
        dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
    {
      _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
                  error.name, error.message);
      dbus_error_free (&error);
      return FALSE;
    }

  dbus_error_free (&error);

  return TRUE;
}
コード例 #6
0
ファイル: dbus-spawn-win.c プロジェクト: psunkari/spicebird
static dbus_bool_t
check_spawn_nonexistent (void *data)
{
  char *argv[4] = { NULL, NULL, NULL, NULL };
  DBusBabysitter *sitter;
  DBusError error;

  sitter = NULL;

  dbus_error_init (&error);

  /*** Test launching nonexistent binary */

  argv[0] = "/this/does/not/exist/32542sdgafgafdg";
  if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
                                         NULL, NULL,
                                         &error))
    {
      _dbus_babysitter_block_for_child_exit (sitter);
      _dbus_babysitter_set_child_exit_error (sitter, &error);
    }

  if (sitter)
    _dbus_babysitter_unref (sitter);

  if (!dbus_error_is_set (&error))
    {
      _dbus_warn ("Did not get an error launching nonexistent executable\n");
      return FALSE;
    }

  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
        dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
    {
      _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
                  error.name, error.message);
      dbus_error_free (&error);
      return FALSE;
    }

  dbus_error_free (&error);

  return TRUE;
}
コード例 #7
0
ファイル: dbus-spawn.c プロジェクト: d-bus/dbus
static dbus_bool_t
handle_watch (DBusWatch       *watch,
              unsigned int     condition,
              void            *data)
{
  DBusBabysitter *sitter = _dbus_babysitter_ref (data);
  int revents;
  int fd;
  
  revents = 0;
  if (condition & DBUS_WATCH_READABLE)
    revents |= _DBUS_POLLIN;
  if (condition & DBUS_WATCH_ERROR)
    revents |= _DBUS_POLLERR;
  if (condition & DBUS_WATCH_HANGUP)
    revents |= _DBUS_POLLHUP;

  fd = dbus_watch_get_socket (watch);

  if (fd == sitter->error_pipe_from_child)
    handle_error_pipe (sitter, revents);
  else if (fd == sitter->socket_to_babysitter.fd)
    handle_babysitter_socket (sitter, revents);

  while (LIVE_CHILDREN (sitter) &&
         babysitter_iteration (sitter, FALSE))
    ;

  /* fd.o #32992: if the handle_* methods closed their sockets, they previously
   * didn't always remove the watches. Check that we don't regress. */
  _dbus_assert (sitter->socket_to_babysitter.fd != -1 || sitter->sitter_watch == NULL);
  _dbus_assert (sitter->error_pipe_from_child != -1 || sitter->error_watch == NULL);

  if (_dbus_babysitter_get_child_exited (sitter) &&
      sitter->finished_cb != NULL)
    {
      sitter->finished_cb (sitter, sitter->finished_data);
      sitter->finished_cb = NULL;
    }

  _dbus_babysitter_unref (sitter);
  return TRUE;
}
コード例 #8
0
ファイル: dbus-spawn.c プロジェクト: mirsal/dbus
static dbus_bool_t
check_spawn_segfault (void *data)
{
    char *argv[4] = { NULL, NULL, NULL, NULL };
    DBusBabysitter *sitter = NULL;
    DBusError error = DBUS_ERROR_INIT;

    /*** Test launching segfault binary */

    argv[0] = TEST_SEGFAULT_BINARY;
    if (_dbus_spawn_async_with_babysitter (&sitter, argv,
                                           NULL, NULL, NULL,
                                           &error))
    {
        _dbus_babysitter_block_for_child_exit (sitter);
        _dbus_babysitter_set_child_exit_error (sitter, &error);
    }

    if (sitter)
        _dbus_babysitter_unref (sitter);

    if (!dbus_error_is_set (&error))
    {
        _dbus_warn ("Did not get an error launching segfaulting binary\n");
        return FALSE;
    }

    if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
            dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)))
    {
        _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
                    error.name, error.message);
        dbus_error_free (&error);
        return FALSE;
    }

    dbus_error_free (&error);

    return TRUE;
}
コード例 #9
0
ファイル: dbus-spawn.c プロジェクト: d-bus/dbus
/**
 * Spawns a new process.
 *
 * On Unix platforms, the child_setup function is passed the given
 * user_data and is run in the child after fork() but before calling exec().
 * This can be used to change uid, resource limits and so on.
 * On Windows, this functionality does not fit the multi-processing model
 * (Windows does the equivalent of fork() and exec() in a single API call),
 * and the child_setup function and its user_data are ignored.
 *
 * Also creates a "babysitter" which tracks the status of the
 * child process, advising the parent if the child exits.
 * If the spawn fails, no babysitter is created.
 * If sitter_p is #NULL, no babysitter is kept.
 *
 * @param sitter_p return location for babysitter or #NULL
 * @param log_name the name under which to log messages about this process being spawned
 * @param argv the executable and arguments
 * @param env the environment, or #NULL to copy the parent's
 * @param child_setup function to call in child pre-exec()
 * @param user_data user data for setup function
 * @param error error object to be filled in if function fails
 * @returns #TRUE on success, #FALSE if error is filled in
 */
dbus_bool_t
_dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
                                   const char               *log_name,
                                   char             * const *argv,
                                   char                    **env,
                                   DBusSpawnFlags            flags,
                                   DBusSpawnChildSetupFunc   child_setup,
                                   void                     *user_data,
                                   DBusError                *error)
{
  DBusBabysitter *sitter;
  int child_err_report_pipe[2] = { -1, -1 };
  DBusSocket babysitter_pipe[2] = { DBUS_SOCKET_INIT, DBUS_SOCKET_INIT };
  pid_t pid;
#ifdef HAVE_SYSTEMD
  int fd_out = -1;
  int fd_err = -1;
#endif
  
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  _dbus_assert (argv[0] != NULL);

  if (sitter_p != NULL)
    *sitter_p = NULL;

  sitter = NULL;

  sitter = _dbus_babysitter_new ();
  if (sitter == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return FALSE;
    }

  sitter->log_name = _dbus_strdup (log_name);
  if (sitter->log_name == NULL && log_name != NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }

  if (sitter->log_name == NULL)
    sitter->log_name = _dbus_strdup (argv[0]);

  if (sitter->log_name == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
  
  if (!make_pipe (child_err_report_pipe, error))
    goto cleanup_and_fail;

  if (!_dbus_socketpair (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
    goto cleanup_and_fail;

  /* Setting up the babysitter is only useful in the parent,
   * but we don't want to run out of memory and fail
   * after we've already forked, since then we'd leak
   * child processes everywhere.
   */
  sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
                                         DBUS_WATCH_READABLE,
                                         TRUE, handle_watch, sitter, NULL);
  if (sitter->error_watch == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
        
  if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->error_watch))
    {
      /* we need to free it early so the destructor won't try to remove it
       * without it having been added, which DBusLoop doesn't allow */
      _dbus_watch_invalidate (sitter->error_watch);
      _dbus_watch_unref (sitter->error_watch);
      sitter->error_watch = NULL;

      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
      
  sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0].fd,
                                          DBUS_WATCH_READABLE,
                                          TRUE, handle_watch, sitter, NULL);
  if (sitter->sitter_watch == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
      
  if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
    {
      /* we need to free it early so the destructor won't try to remove it
       * without it having been added, which DBusLoop doesn't allow */
      _dbus_watch_invalidate (sitter->sitter_watch);
      _dbus_watch_unref (sitter->sitter_watch);
      sitter->sitter_watch = NULL;

      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

#ifdef HAVE_SYSTEMD
  if (flags & DBUS_SPAWN_REDIRECT_OUTPUT)
    {
      /* This may fail, but it's not critical.
       * In particular, if we were compiled with journald support but are now
       * running on a non-systemd system, this is going to fail, so we
       * have to cope gracefully. */
      fd_out = sd_journal_stream_fd (sitter->log_name, LOG_INFO, FALSE);
      fd_err = sd_journal_stream_fd (sitter->log_name, LOG_WARNING, FALSE);
    }
#endif

  pid = fork ();
  
  if (pid < 0)
    {
      dbus_set_error (error,
		      DBUS_ERROR_SPAWN_FORK_FAILED,
		      "Failed to fork (%s)",
		      _dbus_strerror (errno));
      goto cleanup_and_fail;
    }
  else if (pid == 0)
    {
      /* Immediate child, this is the babysitter process. */
      int grandchild_pid;
      
      /* Be sure we crash if the parent exits
       * and we write to the err_report_pipe
       */
      signal (SIGPIPE, SIG_DFL);

      /* Close the parent's end of the pipes. */
      close_and_invalidate (&child_err_report_pipe[READ_END]);
      close_and_invalidate (&babysitter_pipe[0].fd);
      
      /* Create the child that will exec () */
      grandchild_pid = fork ();
      
      if (grandchild_pid < 0)
	{
	  write_err_and_exit (babysitter_pipe[1].fd,
			      CHILD_FORK_FAILED);
          _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
	}
      else if (grandchild_pid == 0)
      {
#ifdef __linux__
          int fd = -1;

#ifdef O_CLOEXEC
          fd = open ("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
#endif

          if (fd < 0)
            {
              fd = open ("/proc/self/oom_score_adj", O_WRONLY);
              _dbus_fd_set_close_on_exec (fd);
            }

          if (fd >= 0)
            {
              if (write (fd, "0", sizeof (char)) < 0)
                _dbus_warn ("writing oom_score_adj error: %s", strerror (errno));
              _dbus_close (fd, NULL);
            }
#endif
          /* Go back to ignoring SIGPIPE, since it's evil
           */
          signal (SIGPIPE, SIG_IGN);

          close_and_invalidate (&babysitter_pipe[1].fd);
#ifdef HAVE_SYSTEMD
	  /* log to systemd journal if possible */
	  if (fd_out >= 0)
            dup2 (fd_out, STDOUT_FILENO);
	  if (fd_err >= 0)
            dup2 (fd_err, STDERR_FILENO);
          close_and_invalidate (&fd_out);
          close_and_invalidate (&fd_err);
#endif
	  do_exec (child_err_report_pipe[WRITE_END],
		   argv,
		   env,
		   child_setup, user_data);
          _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
	}
      else
	{
          close_and_invalidate (&child_err_report_pipe[WRITE_END]);
#ifdef HAVE_SYSTEMD
          close_and_invalidate (&fd_out);
          close_and_invalidate (&fd_err);
#endif
          babysit (grandchild_pid, babysitter_pipe[1].fd);
          _dbus_assert_not_reached ("Got to code after babysit()");
	}
    }
  else
    {      
      /* Close the uncared-about ends of the pipes */
      close_and_invalidate (&child_err_report_pipe[WRITE_END]);
      close_and_invalidate (&babysitter_pipe[1].fd);
#ifdef HAVE_SYSTEMD
      close_and_invalidate (&fd_out);
      close_and_invalidate (&fd_err);
#endif

      sitter->socket_to_babysitter = babysitter_pipe[0];
      babysitter_pipe[0].fd = -1;
      
      sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
      child_err_report_pipe[READ_END] = -1;

      sitter->sitter_pid = pid;

      if (sitter_p != NULL)
        *sitter_p = sitter;
      else
        _dbus_babysitter_unref (sitter);

      dbus_free_string_array (env);

      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
      
      return TRUE;
    }

 cleanup_and_fail:

  _DBUS_ASSERT_ERROR_IS_SET (error);
  
  close_and_invalidate (&child_err_report_pipe[READ_END]);
  close_and_invalidate (&child_err_report_pipe[WRITE_END]);
  close_and_invalidate (&babysitter_pipe[0].fd);
  close_and_invalidate (&babysitter_pipe[1].fd);
#ifdef HAVE_SYSTEMD
  close_and_invalidate (&fd_out);
  close_and_invalidate (&fd_err);
#endif

  if (sitter != NULL)
    _dbus_babysitter_unref (sitter);
  
  return FALSE;
}
コード例 #10
0
ファイル: dbus-spawn-win.c プロジェクト: psunkari/spicebird
dbus_bool_t
_dbus_spawn_async_with_babysitter (DBusBabysitter           **sitter_p,
                                   char                     **argv,
                                   char                     **envp,
                                   DBusSpawnChildSetupFunc    child_setup,
                                   void                      *user_data,
                                   DBusError                 *error)
{
  DBusBabysitter *sitter;
  HANDLE sitter_thread;
  int sitter_thread_id;

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  *sitter_p = NULL;

  PING();
  sitter = _dbus_babysitter_new ();
  if (sitter == NULL)
    {
      _DBUS_SET_OOM (error);
      return FALSE;
    }

  sitter->child_setup = child_setup;
  sitter->user_data = user_data;

  sitter->executable = _dbus_strdup (argv[0]);
  if (sitter->executable == NULL)
    {
      _DBUS_SET_OOM (error);
      goto out0;
    }

  PING();
  if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter,
                               &sitter->socket_to_main,
                               FALSE, error))
    goto out0;

  sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter,
                                          DBUS_WATCH_READABLE,
                                          TRUE, handle_watch, sitter, NULL);
  PING();
  if (sitter->sitter_watch == NULL)
    {
      _DBUS_SET_OOM (error);
      goto out0;
    }

  PING();
  if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
    {
      _DBUS_SET_OOM (error);
      goto out0;
    }

  sitter->argc = protect_argv (argv, &sitter->argv);
  if (sitter->argc == -1)
    {
      _DBUS_SET_OOM (error);
      goto out0;
    }
  sitter->envp = envp;

  PING();
  sitter_thread = (HANDLE) _beginthreadex (NULL, 0, babysitter,
                  sitter, 0, &sitter_thread_id);

  if (sitter_thread == 0)
    {
      PING();
      dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED,
                            "Failed to create new thread");
      goto out0;
    }
  CloseHandle (sitter_thread);

  PING();
  WaitForSingleObject (sitter->start_sync_event, INFINITE);

  PING();
  if (sitter_p != NULL)
    *sitter_p = sitter;
  else
    _dbus_babysitter_unref (sitter);

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  PING();
  return TRUE;

out0:
  _dbus_babysitter_unref (sitter);

  return FALSE;
}
コード例 #11
0
ファイル: dbus-spawn-win.c プロジェクト: psunkari/spicebird
static unsigned __stdcall
babysitter (void *parameter)
{
  DBusBabysitter *sitter = (DBusBabysitter *) parameter;
  int fd;
  PING();
  _dbus_babysitter_ref (sitter);

  if (sitter->child_setup)
    {
      PING();
      (*sitter->child_setup) (sitter->user_data);
    }

  _dbus_verbose ("babysitter: spawning %s\n", sitter->executable);

  PING();
  if (sitter->envp != NULL)
    sitter->child_handle = (HANDLE) spawnve (P_NOWAIT, sitter->executable,
                           (const char * const *) sitter->argv,
                           (const char * const *) sitter->envp);
  else
    sitter->child_handle = (HANDLE) spawnv (P_NOWAIT, sitter->executable,
                                            (const char * const *) sitter->argv);

  PING();
  if (sitter->child_handle == (HANDLE) -1)
    {
      sitter->child_handle = NULL;
      sitter->have_spawn_errno = TRUE;
      sitter->spawn_errno = errno;
    }

  PING();
  SetEvent (sitter->start_sync_event);

  if (sitter->child_handle != NULL)
    {
      int ret;
      DWORD status;

      PING();
      WaitForSingleObject (sitter->child_handle, INFINITE);

      PING();
      ret = GetExitCodeProcess (sitter->child_handle, &status);

      sitter->child_status = status;
      sitter->have_child_status = TRUE;

      CloseHandle (sitter->child_handle);
      sitter->child_handle = NULL;
    }

#ifdef DBUS_BUILD_TESTS
  SetEvent (sitter->end_sync_event);
#endif

  PING();
  send (sitter->socket_to_main, " ", 1, 0);

  _dbus_babysitter_unref (sitter);

  return 0;
}
コード例 #12
0
ファイル: dbus-spawn.c プロジェクト: mirsal/dbus
/**
 * Spawns a new process. The executable name and argv[0]
 * are the same, both are provided in argv[0]. The child_setup
 * function is passed the given user_data and is run in the child
 * just before calling exec().
 *
 * Also creates a "babysitter" which tracks the status of the
 * child process, advising the parent if the child exits.
 * If the spawn fails, no babysitter is created.
 * If sitter_p is #NULL, no babysitter is kept.
 *
 * @param sitter_p return location for babysitter or #NULL
 * @param argv the executable and arguments
 * @param env the environment (not used on unix yet)
 * @param child_setup function to call in child pre-exec()
 * @param user_data user data for setup function
 * @param error error object to be filled in if function fails
 * @returns #TRUE on success, #FALSE if error is filled in
 */
dbus_bool_t
_dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
                                   char                    **argv,
                                   char                    **env,
                                   DBusSpawnChildSetupFunc   child_setup,
                                   void                     *user_data,
                                   DBusError                *error)
{
    DBusBabysitter *sitter;
    int child_err_report_pipe[2] = { -1, -1 };
    int babysitter_pipe[2] = { -1, -1 };
    pid_t pid;

    _DBUS_ASSERT_ERROR_IS_CLEAR (error);

    if (sitter_p != NULL)
        *sitter_p = NULL;

    sitter = NULL;

    sitter = _dbus_babysitter_new ();
    if (sitter == NULL)
    {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        return FALSE;
    }

    sitter->executable = _dbus_strdup (argv[0]);
    if (sitter->executable == NULL)
    {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        goto cleanup_and_fail;
    }

    if (!make_pipe (child_err_report_pipe, error))
        goto cleanup_and_fail;

    if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
        goto cleanup_and_fail;

    /* Setting up the babysitter is only useful in the parent,
     * but we don't want to run out of memory and fail
     * after we've already forked, since then we'd leak
     * child processes everywhere.
     */
    sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
                                           DBUS_WATCH_READABLE,
                                           TRUE, handle_watch, sitter, NULL);
    if (sitter->error_watch == NULL)
    {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        goto cleanup_and_fail;
    }

    if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->error_watch))
    {
        /* we need to free it early so the destructor won't try to remove it
         * without it having been added, which DBusLoop doesn't allow */
        _dbus_watch_invalidate (sitter->error_watch);
        _dbus_watch_unref (sitter->error_watch);
        sitter->error_watch = NULL;

        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        goto cleanup_and_fail;
    }

    sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0],
                                            DBUS_WATCH_READABLE,
                                            TRUE, handle_watch, sitter, NULL);
    if (sitter->sitter_watch == NULL)
    {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        goto cleanup_and_fail;
    }

    if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
    {
        /* we need to free it early so the destructor won't try to remove it
         * without it having been added, which DBusLoop doesn't allow */
        _dbus_watch_invalidate (sitter->sitter_watch);
        _dbus_watch_unref (sitter->sitter_watch);
        sitter->sitter_watch = NULL;

        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        goto cleanup_and_fail;
    }

    _DBUS_ASSERT_ERROR_IS_CLEAR (error);

    pid = fork ();

    if (pid < 0)
    {
        dbus_set_error (error,
                        DBUS_ERROR_SPAWN_FORK_FAILED,
                        "Failed to fork (%s)",
                        _dbus_strerror (errno));
        goto cleanup_and_fail;
    }
    else if (pid == 0)
    {
        /* Immediate child, this is the babysitter process. */
        int grandchild_pid;

        /* Be sure we crash if the parent exits
         * and we write to the err_report_pipe
         */
        signal (SIGPIPE, SIG_DFL);

        /* Close the parent's end of the pipes. */
        close_and_invalidate (&child_err_report_pipe[READ_END]);
        close_and_invalidate (&babysitter_pipe[0]);

        /* Create the child that will exec () */
        grandchild_pid = fork ();

        if (grandchild_pid < 0)
        {
            write_err_and_exit (babysitter_pipe[1],
                                CHILD_FORK_FAILED);
            _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
        }
        else if (grandchild_pid == 0)
        {
            do_exec (child_err_report_pipe[WRITE_END],
                     argv,
                     env,
                     child_setup, user_data);
            _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
        }
        else
        {
            babysit (grandchild_pid, babysitter_pipe[1]);
            _dbus_assert_not_reached ("Got to code after babysit()");
        }
    }
    else
    {
        /* Close the uncared-about ends of the pipes */
        close_and_invalidate (&child_err_report_pipe[WRITE_END]);
        close_and_invalidate (&babysitter_pipe[1]);

        sitter->socket_to_babysitter = babysitter_pipe[0];
        babysitter_pipe[0] = -1;

        sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
        child_err_report_pipe[READ_END] = -1;

        sitter->sitter_pid = pid;

        if (sitter_p != NULL)
            *sitter_p = sitter;
        else
            _dbus_babysitter_unref (sitter);

        dbus_free_string_array (env);

        _DBUS_ASSERT_ERROR_IS_CLEAR (error);

        return TRUE;
    }

cleanup_and_fail:

    _DBUS_ASSERT_ERROR_IS_SET (error);

    close_and_invalidate (&child_err_report_pipe[READ_END]);
    close_and_invalidate (&child_err_report_pipe[WRITE_END]);
    close_and_invalidate (&babysitter_pipe[0]);
    close_and_invalidate (&babysitter_pipe[1]);

    if (sitter != NULL)
        _dbus_babysitter_unref (sitter);

    return FALSE;
}
コード例 #13
0
ファイル: dbus-spawn.c プロジェクト: cdaffara/symbiandump-os2
EXPORT_C
#endif
dbus_bool_t
_dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
                                   char                    **argv,
                                   DBusSpawnChildSetupFunc   child_setup,
                                   void                     *user_data,
                                   DBusError                *error)
{

#ifndef __SYMBIAN32__
  DBusBabysitter *sitter;
  int child_err_report_pipe[2] = { -1, -1 };
  int babysitter_pipe[2] = { -1, -1 };
  pid_t pid;
  
  #ifndef __SYMBIAN32__
  _DBUS_ASSERT_ERROR_IS_CLEAR (error);

  *sitter_p = NULL;
  sitter = NULL;

  sitter = _dbus_babysitter_new ();
  if (sitter == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      return FALSE;
    }

  sitter->executable = _dbus_strdup (argv[0]);
  if (sitter->executable == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
  
  if (!make_pipe (child_err_report_pipe, error))
    goto cleanup_and_fail;

  _dbus_fd_set_close_on_exec (child_err_report_pipe[READ_END]);
  _dbus_fd_set_close_on_exec (child_err_report_pipe[WRITE_END]);

  if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
    goto cleanup_and_fail;

  _dbus_fd_set_close_on_exec (babysitter_pipe[0]);
  _dbus_fd_set_close_on_exec (babysitter_pipe[1]);

  /* Setting up the babysitter is only useful in the parent,
   * but we don't want to run out of memory and fail
   * after we've already forked, since then we'd leak
   * child processes everywhere.
   */
  sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END],
                                         DBUS_WATCH_READABLE,
                                         TRUE, handle_watch, sitter, NULL);
  if (sitter->error_watch == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
        
  if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->error_watch))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
      
  sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0],
                                          DBUS_WATCH_READABLE,
                                          TRUE, handle_watch, sitter, NULL);
  if (sitter->sitter_watch == NULL)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }
      
  if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
      goto cleanup_and_fail;
    }

  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  
  pid = fork ();
  
  if (pid < 0)
    {
      dbus_set_error (error,
		      DBUS_ERROR_SPAWN_FORK_FAILED,
		      "Failed to fork (%s)",
		      _dbus_strerror (errno));
      goto cleanup_and_fail;
    }
  else if (pid == 0)
    {
      /* Immediate child, this is the babysitter process. */
      int grandchild_pid;
      
      /* Be sure we crash if the parent exits
       * and we write to the err_report_pipe
       */
#ifndef __SYMBIAN32__       
      signal (SIGPIPE, SIG_DFL);
#endif      

      /* Close the parent's end of the pipes. */
      close_and_invalidate (&child_err_report_pipe[READ_END]);
      close_and_invalidate (&babysitter_pipe[0]);
      
      /* Create the child that will exec () */
      grandchild_pid = fork ();
      
      if (grandchild_pid < 0)
	{
	  write_err_and_exit (babysitter_pipe[1],
			      CHILD_FORK_FAILED);
          _dbus_assert_not_reached ("Got to code after write_err_and_exit()");
	}
      else if (grandchild_pid == 0)
	{
	  do_exec (child_err_report_pipe[WRITE_END],
		   argv,
		   child_setup, user_data);
          _dbus_assert_not_reached ("Got to code after exec() - should have exited on error");
	}
      else
	{
          babysit (grandchild_pid, babysitter_pipe[1]);
          _dbus_assert_not_reached ("Got to code after babysit()");
	}
    }
  else
    {      
      /* Close the uncared-about ends of the pipes */
      close_and_invalidate (&child_err_report_pipe[WRITE_END]);
      close_and_invalidate (&babysitter_pipe[1]);

      sitter->socket_to_babysitter = babysitter_pipe[0];
      babysitter_pipe[0] = -1;
      
      sitter->error_pipe_from_child = child_err_report_pipe[READ_END];
      child_err_report_pipe[READ_END] = -1;

      sitter->sitter_pid = pid;

      if (sitter_p != NULL)
        *sitter_p = sitter;
      else
        _dbus_babysitter_unref (sitter);

      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
      
      return TRUE;
    }

 cleanup_and_fail:

  _DBUS_ASSERT_ERROR_IS_SET (error);
  
  close_and_invalidate (&child_err_report_pipe[READ_END]);
  close_and_invalidate (&child_err_report_pipe[WRITE_END]);
  close_and_invalidate (&babysitter_pipe[0]);
  close_and_invalidate (&babysitter_pipe[1]);

  if (sitter != NULL)
    _dbus_babysitter_unref (sitter);
  #endif
  return FALSE;
  
  
#else


/*
FILE* ChildProcessStream;
 ChildProcessStream =popen(argv[0], "r");
	if (ChildProcessStream == NULL)
	{
	 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
                      "Failed to execute service process");
     	 return FALSE;
      
	}
*/
 //static pid_t Childpid; //have to make it static for thread fuction to access it
 pid_t childPid;
 int retVal; 
 
 //pthread_t thread;

 retVal = posix_spawn(&childPid, argv[0], NULL,NULL, NULL, NULL);
  	if (retVal!=0)
	{
	 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
                      "Failed to execute service process");
     	 return FALSE;
      
	}

/*
 pthread_create(&thread, NULL, (void*)&thread_fun, &Childpid);
//(void) waitpid(Childpid, NULL, 0);
//printf("\r\n*** Child process finished ***\r\n");

*/

if(!retVal)
	return TRUE;
else
	return FALSE;

#endif  
}