/** * 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(); }
/** * 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; }
/** * 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; }
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); } }
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; }