Example #1
0
/**
 * Sets the #DBusError with an explanation of why the spawned
 * child process exited (on a signal, or whatever). If
 * the child process has not exited, does nothing (error
 * will remain unset).
 *
 * @param sitter the babysitter
 * @param error an error to fill in
 */
void
_dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
                                       DBusError      *error)
{
  PING();
  if (!_dbus_babysitter_get_child_exited (sitter))
    return;

  PING();
  if (sitter->have_spawn_errno)
    {
      dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
                      "Failed to execute program %s: %s",
                      sitter->executable, _dbus_strerror (sitter->spawn_errno));
    }
  else if (sitter->have_child_status)
    {
      PING();
      dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
                      "Process %s exited with status %d",
                      sitter->executable, sitter->child_status);
    }
  else
    {
      PING();
      dbus_set_error (error, DBUS_ERROR_FAILED,
                      "Process %s exited, status unknown",
                      sitter->executable);
    }
  PING();
}
Example #2
0
/**
 * Gets the exit status of the child. We do this so implementation specific
 * detail is not cluttering up dbus, for example the system launcher code.
 * This can only be called if the child has exited, i.e. call
 * _dbus_babysitter_get_child_exited(). It returns FALSE if the child
 * did not return a status code, e.g. because the child was signaled
 * or we failed to ever launch the child in the first place.
 *
 * @param sitter the babysitter
 * @param status the returned status code
 * @returns #FALSE on failure
 */
dbus_bool_t
_dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter,
                                        int            *status)
{
  if (!_dbus_babysitter_get_child_exited (sitter))
    _dbus_assert_not_reached ("Child has not exited");
  
  if (!sitter->have_child_status ||
      !(WIFEXITED (sitter->status)))
    return FALSE;

  *status = WEXITSTATUS (sitter->status);
  return TRUE;
}
Example #3
0
/**
 * Gets the exit status of the child. We do this so implementation specific
 * detail is not cluttering up dbus, for example the system launcher code.
 * This can only be called if the child has exited, i.e. call
 * _dbus_babysitter_get_child_exited(). It returns FALSE if the child
 * did not return a status code, e.g. because the child was signaled
 * or we failed to ever launch the child in the first place.
 *
 * @param sitter the babysitter
 * @param status the returned status code
 * @returns #FALSE on failure
 */
dbus_bool_t
_dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter,
                                        int            *status)
{
  if (!_dbus_babysitter_get_child_exited (sitter))
    _dbus_assert_not_reached ("Child has not exited");

  if (!sitter->have_child_status ||
      sitter->child_status == STILL_ACTIVE)
    return FALSE;

  *status = sitter->child_status;
  return TRUE;
}
Example #4
0
EXPORT_C
#endif
void
_dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
                                       DBusError      *error)
{
  if (!_dbus_babysitter_get_child_exited (sitter))
    return;

  /* Note that if exec fails, we will also get a child status
   * from the babysitter saying the child exited,
   * so we need to give priority to the exec error
   */
  if (sitter->have_exec_errnum)
    {
      dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
                      "Failed to execute program %s: %s",
                      sitter->executable, _dbus_strerror (sitter->errnum));
    }
  else if (sitter->have_fork_errnum)
    {
      dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
                      "Failed to fork a new process %s: %s",
                      sitter->executable, _dbus_strerror (sitter->errnum));
    }
  else if (sitter->have_child_status)
    {
      if (WIFEXITED (sitter->status))
        dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
                        "Process %s exited with status %d",
                        sitter->executable, WEXITSTATUS (sitter->status));
      else if (WIFSIGNALED (sitter->status))
        dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_SIGNALED,
                        "Process %s received signal %d",
                        sitter->executable, WTERMSIG (sitter->status));
      else
        dbus_set_error (error, DBUS_ERROR_FAILED,
                        "Process %s exited abnormally",
                        sitter->executable);
    }
  else
    {
      dbus_set_error (error, DBUS_ERROR_FAILED,
                      "Process %s exited, reason unknown",
                      sitter->executable);
    }
}
Example #5
0
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;
}