From 6140ec2de332ebdb618bdccf8c3c28b97eb6bde1 Mon Sep 17 00:00:00 2001 From: Tommy Lindgren Date: Wed, 13 Oct 2010 15:31:06 +0200 Subject: [PATCH] Add libssh2_channel_get_exit_signal. Signed-off-by: Simon Josefsson --- docs/Makefile.am | 1 + example/ssh2_exec.c | 8 +++++- include/libssh2.h | 7 +++++ src/channel.c | 65 +++++++++++++++++++++++++++++++++++++++++++++ src/libssh2_priv.h | 3 +++ src/packet.c | 34 ++++++++++++++++++++++++ 6 files changed, 117 insertions(+), 1 deletion(-) diff --git a/docs/Makefile.am b/docs/Makefile.am index 4ed40df..1fdfc38 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -26,6 +26,7 @@ dist_man_MANS = \ libssh2_channel_forward_listen_ex.3 \ libssh2_channel_free.3 \ libssh2_channel_get_exit_status.3 \ + libssh2_channel_get_exit_signal.3 \ libssh2_channel_handle_extended_data.3 \ libssh2_channel_handle_extended_data2.3 \ libssh2_channel_ignore_extended_data.3 \ diff --git a/example/ssh2_exec.c b/example/ssh2_exec.c index 1b74abc..90d81c5 100644 --- a/example/ssh2_exec.c +++ b/example/ssh2_exec.c @@ -86,6 +86,7 @@ int main(int argc, char *argv[]) LIBSSH2_CHANNEL *channel; int rc; int exitcode; + char *exitsignal; int bytecount = 0; size_t len; LIBSSH2_KNOWNHOSTS *nh; @@ -286,8 +287,13 @@ int main(int argc, char *argv[]) if( rc == 0 ) { exitcode = libssh2_channel_get_exit_status( channel ); + libssh2_channel_get_exit_signal(channel, &exitsignal, NULL, NULL, NULL, NULL, NULL); } - printf("\nEXIT: %d bytecount: %d\n", exitcode, bytecount); + + if (exitsignal) + printf("\nGot signal: %s\n", exitsignal); + else + printf("\nEXIT: %d bytecount: %d\n", exitcode, bytecount); libssh2_channel_free(channel); channel = NULL; diff --git a/include/libssh2.h b/include/libssh2.h index 038b61f..eedfecf 100644 --- a/include/libssh2.h +++ b/include/libssh2.h @@ -730,6 +730,13 @@ LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR) LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel); +LIBSSH2_API int libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL* channel, + char **exitsignal, + size_t *exitsignal_len, + char **errmsg, + size_t *errmsg_len, + char **langtag, + size_t *langtag_len); LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel); LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel); LIBSSH2_API int libssh2_channel_wait_eof(LIBSSH2_CHANNEL *channel); diff --git a/src/channel.c b/src/channel.c index 3393beb..41b2cef 100644 --- a/src/channel.c +++ b/src/channel.c @@ -1476,6 +1476,67 @@ libssh2_channel_get_exit_status(LIBSSH2_CHANNEL *channel) return channel->exit_status; } +/* + * libssh2_channel_get_exit_signal + * + * Get exit signal (without leading "SIG"), error message, and language + * tag into newly allocated buffers of indicated length. Caller can + * use NULL pointers to indicate that the value should not be set. The + * *_len variables are set if they are non-NULL even if the + * corresponding string parameter is NULL. Returns LIBSSH2_ERROR_NONE + * on success, or an API error code. + */ +LIBSSH2_API int +libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL *channel, + char **exitsignal, + size_t *exitsignal_len, + char **errmsg, + size_t *errmsg_len, + char **langtag, + size_t *langtag_len) +{ + LIBSSH2_SESSION *session = channel->session; + size_t namelen = 0; + + if (channel) { + if (channel->exit_signal) { + namelen = strlen(channel->exit_signal); + if (exitsignal) { + *exitsignal = LIBSSH2_ALLOC(session, namelen + 1); + if (!*exitsignal) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for signal name"); + } + memcpy(*exitsignal, channel->exit_signal, namelen); + (*exitsignal)[namelen] = '\0'; + } + if (exitsignal_len) + *exitsignal_len = namelen; + } else { + if (exitsignal) + *exitsignal = NULL; + if (exitsignal_len) + *exitsignal_len = 0; + } + + /* TODO: set error message and language tag */ + + if (errmsg) + *errmsg = NULL; + + if (errmsg_len) + *errmsg_len = 0; + + if (langtag) + *langtag = NULL; + + if (langtag_len) + *langtag_len = 0; + } + + return LIBSSH2_ERROR_NONE; +} + /* * _libssh2_channel_receive_window_adjust * @@ -2413,6 +2474,10 @@ int _libssh2_channel_free(LIBSSH2_CHANNEL *channel) channel->free_state = libssh2_NB_state_idle; + if (channel->exit_signal) { + LIBSSH2_FREE(session, channel->exit_signal); + } + /* * channel->remote.close *might* not be set yet, Well... * We've sent the close packet, what more do you want? diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h index 4200641..f1aaf08 100644 --- a/src/libssh2_priv.h +++ b/src/libssh2_priv.h @@ -340,6 +340,9 @@ struct _LIBSSH2_CHANNEL /* channel's program exit status */ int exit_status; + /* channel's program exit signal (without the SIG prefix) */ + char *exit_signal; + libssh2_channel_data local, remote; /* Amount of bytes to be refunded to receive window (but not yet sent) */ unsigned long adjust_queue; diff --git a/src/packet.c b/src/packet.c index 8315f9c..bcf84bb 100644 --- a/src/packet.c +++ b/src/packet.c @@ -762,6 +762,40 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, return 0; } + if (strlen == sizeof("exit-signal") - 1 + && !memcmp("exit-signal", data + 9, + sizeof("exit-signal") - 1)) { + + /* command terminated due to signal */ + session->packAdd_channel = + _libssh2_channel_locate(session, channel); + + if (session->packAdd_channel) { + /* set signal name (without SIG prefix) */ + uint32_t namelen = _libssh2_ntohu32(data + 9 + sizeof("exit-signal")); + session->packAdd_channel->exit_signal = + LIBSSH2_ALLOC(session, namelen + 1); + if (!session->packAdd_channel->exit_signal) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for signal name"); + } else { + memcpy(session->packAdd_channel->exit_signal, + data + 13 + sizeof("exit_signal"), namelen); + session->packAdd_channel->exit_signal[namelen] = '\0'; + /* TODO: save error message and language tag */ + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Exit signal %s received for channel %lu/%lu", + session->packAdd_channel->exit_signal, + session->packAdd_channel->local.id, + session->packAdd_channel->remote.id); + } + } + + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return 0; + } + if (want_reply) { libssh2_packet_add_jump_point4: session->packAdd_state = libssh2_NB_state_jump4;