summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--common-channel.c52
-rw-r--r--svr-chansession.c3
2 files changed, 29 insertions, 26 deletions
diff --git a/common-channel.c b/common-channel.c
index 5765f07..0cd6ef8 100644
--- a/common-channel.c
+++ b/common-channel.c
@@ -181,6 +181,7 @@ void channelio(fd_set *readfds, fd_set *writefds) {
struct Channel *channel;
unsigned int i;
+ int ret;
/* iterate through all the possible channels */
for (i = 0; i < ses.chansize; i++) {
@@ -204,7 +205,8 @@ void channelio(fd_set *readfds, fd_set *writefds) {
/* if we can read from the writefd, it might be closed, so we try to
* see if it has errors */
- if (channel->writefd >= 0 && channel->writefd != channel->readfd
+ if (IS_DROPBEAR_SERVER && channel->writefd >= 0
+ && channel->writefd != channel->readfd
&& FD_ISSET(channel->writefd, readfds)) {
if (channel->initconn) {
/* Handling for "in progress" connection - this is needed
@@ -259,27 +261,27 @@ static void checkclose(struct Channel *channel) {
channel->writebuf,
channel->writebuf ? 0 : cbuf_getused(channel->extrabuf)))
- if (!channel->sentclosed) {
-
- /* check for exited - currently only used for server sessions,
- * if the shell has exited etc */
- if (channel->type->checkclose) {
- if (channel->type->checkclose(channel)) {
- closewritefd(channel);
- }
+ /* server chansession channels are special, since readfd mightn't
+ * close in the case of "sleep 4 & echo blah" until the sleep is up */
+ if (channel->type->checkclose) {
+ if (channel->type->checkclose(channel)) {
+ closewritefd(channel);
+ closereadfd(channel, channel->readfd);
+ closereadfd(channel, channel->errfd);
}
+ }
- if (!channel->senteof
- && channel->readfd == FD_CLOSED
- && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
- send_msg_channel_eof(channel);
- }
+ if (!channel->senteof
+ && channel->readfd == FD_CLOSED
+ && (channel->extrabuf == NULL || channel->errfd == FD_CLOSED)) {
+ send_msg_channel_eof(channel);
+ }
- if (channel->writefd == FD_CLOSED
- && channel->readfd == FD_CLOSED
- && (channel->extrabuf != NULL || channel->errfd == FD_CLOSED)) {
- send_msg_channel_close(channel);
- }
+ if (!channel->sentclosed
+ && channel->writefd == FD_CLOSED
+ && channel->readfd == FD_CLOSED
+ && (channel->extrabuf == NULL || channel->errfd == FD_CLOSED)) {
+ send_msg_channel_close(channel);
}
/* When either party wishes to terminate the channel, it sends
@@ -444,20 +446,22 @@ void setchannelfds(fd_set *readfds, fd_set *writefds) {
}
}
- /* For checking FD status (ie closure etc) - we don't actually
- * read data from writefd */
TRACE(("writefd = %d, readfd %d, errfd %d, bufused %d",
channel->writefd, channel->readfd,
channel->errfd,
cbuf_getused(channel->writebuf) ))
- if (channel->writefd >= 0 && channel->writefd != channel->readfd) {
+
+ /* For checking FD status (ie closure etc) - we don't actually
+ * read data from writefd. We don't want to do this for the client,
+ * since redirection to /dev/null will make it spin in the select */
+ if (IS_DROPBEAR_SERVER && channel->writefd >= 0
+ && channel->writefd != channel->readfd) {
FD_SET(channel->writefd, readfds);
}
- /* Stuff from the wire, to local program/shell/user etc */
+ /* Stuff from the wire */
if ((channel->writefd >= 0 && cbuf_getused(channel->writebuf) > 0 )
|| channel->initconn) {
-
FD_SET(channel->writefd, writefds);
}
diff --git a/svr-chansession.c b/svr-chansession.c
index 605bb60..fed8240 100644
--- a/svr-chansession.c
+++ b/svr-chansession.c
@@ -67,8 +67,7 @@ static void get_termmodes(struct ChanSess *chansess);
extern char** environ;
static int sesscheckclose(struct Channel *channel) {
- struct ChanSess *chansess = (struct ChanSess*)channel->typedata;
- return chansess->exit.exitpid >= 0;
+ return channel->writefd == -1;
}
/* Handler for childs exiting, store the state for return to the client */