1
0
mirror of https://git.libssh.org/projects/libssh.git synced 2025-08-05 20:55:46 +03:00

channels: Implement better ssh_channel_get_exit_state() variant

This way we will get errors as return code else we don't know if the
function failed (SSH_ERROR) or the exit_status is -1 which would
correspond to SSH_ERROR.

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
This commit is contained in:
Andreas Schneider
2022-09-08 14:38:18 +02:00
parent d40a6448a4
commit 04d86aeeae
4 changed files with 111 additions and 17 deletions

View File

@@ -462,7 +462,11 @@ LIBSSH_API int ssh_channel_close(ssh_channel channel);
} \
} while (0)
LIBSSH_API void ssh_channel_free(ssh_channel channel);
LIBSSH_API int ssh_channel_get_exit_status(ssh_channel channel);
LIBSSH_API int ssh_channel_get_exit_state(ssh_channel channel,
uint32_t *pexit_code,
char **pexit_signal,
int *pcore_dumped);
SSH_DEPRECATED LIBSSH_API int ssh_channel_get_exit_status(ssh_channel channel);
LIBSSH_API ssh_session ssh_channel_get_session(ssh_channel channel);
LIBSSH_API int ssh_channel_is_closed(ssh_channel channel);
LIBSSH_API int ssh_channel_is_eof(ssh_channel channel);

View File

@@ -498,8 +498,22 @@ public:
return_throwable;
}
int getExitStatus(){
return ssh_channel_get_exit_status(channel);
/*
* @deprecated Please use getExitState()
*/
int getExitStatus() {
uint32_t exit_status = (uint32_t)-1;
ssh_channel_get_exit_state(channel, &exit_status, NULL, NULL);
return exit_status;
}
void_throwable getExitState(uint32_t & pexit_code,
char **pexit_signal,
int & pcore_dumped) {
ssh_throw(ssh_channel_get_exit_state(channel,
&pexit_code,
pexit_signal,
&pcore_dumped));
return_throwable;
}
Session &getSession(){
return *session;

View File

@@ -3388,6 +3388,83 @@ static int ssh_channel_exit_status_termination(void *c)
return 0;
}
/**
* @brief Get the exit state of the channel (error code from the executed
* instruction or signal).
*
* @param[in] channel The channel to get the status from.
*
* @param[out] pexit_code A pointer to an uint32_t to store the exit status.
*
* @param[out] pexit_signal A pointer to store the exit signal as a string.
* The signal is without the SIG prefix, e.g. "TERM" or
* "KILL"). The caller has to free the memory.
*
* @param[out] pcore_dumped A pointer to store a boolean value if it dumped a
* core.
*
* @return SSH_OK on success, SSH_AGAIN if we don't have a status
* or an SSH error.
* @warning This function may block until a timeout (or never)
* if the other side is not willing to close the channel.
* When a channel is freed the function returns
* SSH_ERROR immediately.
*
* If you're looking for an async handling of this register a callback for the
* exit status!
*
* @see ssh_channel_exit_status_callback
* @see ssh_channel_exit_signal_callback
*/
int ssh_channel_get_exit_state(ssh_channel channel,
uint32_t *pexit_code,
char **pexit_signal,
int *pcore_dumped)
{
ssh_session session = NULL;
int rc;
if ((channel == NULL) || (channel->flags & SSH_CHANNEL_FLAG_FREED_LOCAL)) {
return SSH_ERROR;
}
session = channel->session;
rc = ssh_handle_packets_termination(channel->session,
SSH_TIMEOUT_DEFAULT,
ssh_channel_exit_status_termination,
channel);
if (rc == SSH_ERROR || channel->session->session_state ==
SSH_SESSION_STATE_ERROR) {
return SSH_ERROR;
}
/* If we don't have any kind of exit state, return SSH_AGAIN */
if (!channel->exit.status) {
return SSH_AGAIN;
}
if (pexit_code != NULL) {
*pexit_code = channel->exit.code;
}
if (pexit_signal != NULL) {
*pexit_signal = NULL;
if (channel->exit.signal != NULL) {
*pexit_signal = strdup(channel->exit.signal);
if (pexit_signal == NULL) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
}
}
if (pcore_dumped != NULL) {
*pcore_dumped = channel->exit.core_dumped;
}
return SSH_OK;
}
/**
* @brief Get the exit status of the channel (error code from the executed
* instruction).
@@ -3405,21 +3482,19 @@ static int ssh_channel_exit_status_termination(void *c)
* exit status.
*
* @see ssh_channel_exit_status_callback
* @deprecated Please use ssh_channel_exit_state()
*/
int ssh_channel_get_exit_status(ssh_channel channel)
{
uint32_t exit_status = (uint32_t)-1;
int rc;
if ((channel == NULL) || (channel->flags & SSH_CHANNEL_FLAG_FREED_LOCAL)) {
rc = ssh_channel_get_exit_state(channel, &exit_status, NULL, NULL);
if (rc != SSH_OK) {
return SSH_ERROR;
}
rc = ssh_handle_packets_termination(channel->session,
SSH_TIMEOUT_DEFAULT,
ssh_channel_exit_status_termination,
channel);
if (rc == SSH_ERROR || channel->session->session_state ==
SSH_SESSION_STATE_ERROR)
return SSH_ERROR;
return channel->exit.code;
return exit_status;
}
/*

View File

@@ -403,7 +403,7 @@ static void torture_channel_exit_status(void **state)
ssh_session session = s->ssh.session;
ssh_channel channel = NULL;
char request[256];
int exit_status = -1;
uint32_t exit_status = (uint32_t)-1;
int rc;
rc = snprintf(request, sizeof(request), "true");
@@ -419,7 +419,8 @@ static void torture_channel_exit_status(void **state)
rc = ssh_channel_request_exec(channel, request);
assert_ssh_return_code(session, rc);
exit_status = ssh_channel_get_exit_status(channel);
exit_status = ssh_channel_get_exit_state(channel, &exit_status, NULL, NULL);
assert_ssh_return_code(session, rc);
assert_int_equal(exit_status, 0);
}