changeset 423:b2b67cfcd66e channel-fix

- Fix bug in child-exit handling where the wrong pid was being matched. - Also wait for errfd to close before closing the channel
author Matt Johnston <matt@ucc.asn.au>
date Mon, 12 Feb 2007 10:39:22 +0000
parents a9e0ddac5ba7
children db976892c67f
files common-channel.c svr-chansession.c
diffstat 2 files changed, 17 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/common-channel.c	Mon Feb 12 10:37:35 2007 +0000
+++ b/common-channel.c	Mon Feb 12 10:39:22 2007 +0000
@@ -313,6 +313,7 @@
 	/* And if we can't receive any more data from them either, close up */
 	if (!channel->sent_close
 			&& channel->readfd == FD_CLOSED
+			&& (ERRFD_IS_WRITE(channel) || channel->errfd == FD_CLOSED)
 			&& !write_pending(channel)) {
 		TRACE(("sending close, readfd is closed"))
 		send_msg_channel_close(channel);
@@ -624,8 +625,8 @@
 			close_chan_fd(channel, fd, SHUT_RD);
 		}
 		ses.writepayload->len = ses.writepayload->pos = 0;
-		TRACE(("leave send_msg_channel_data: len %d read err or EOF for fd %d", 
-					len, channel->index));
+		TRACE(("leave send_msg_channel_data: len %d read err %d or EOF for fd %d", 
+					len, errno, fd))
 		return;
 	}
 	buf_incrwritepos(ses.writepayload, len);
--- a/svr-chansession.c	Mon Feb 12 10:37:35 2007 +0000
+++ b/svr-chansession.c	Mon Feb 12 10:39:22 2007 +0000
@@ -67,6 +67,7 @@
 
 static int sesscheckclose(struct Channel *channel) {
 	struct ChanSess *chansess = (struct ChanSess*)channel->typedata;
+	TRACE(("sesscheckclose, pid is %d", chansess->exit.exitpid))
 	return chansess->exit.exitpid != -1;
 }
 
@@ -88,12 +89,13 @@
 
 	TRACE(("enter sigchld handler"))
 	while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+		TRACE(("sigchld handler: pid %d", pid))
 
 		exit = NULL;
 		/* find the corresponding chansess */
 		for (i = 0; i < svr_ses.childpidsize; i++) {
 			if (svr_ses.childpids[i].pid == pid) {
-
+				TRACE(("found match session"));
 				exit = &svr_ses.childpids[i].chansess->exit;
 				break;
 			}
@@ -102,6 +104,7 @@
 		/* If the pid wasn't matched, then we might have hit the race mentioned
 		 * above. So we just store the info for the parent to deal with */
 		if (exit == NULL) {
+			TRACE(("using lastexit"));
 			exit = &svr_ses.lastexit;
 		}
 
@@ -125,7 +128,8 @@
 		while (1) {
 			/* EAGAIN means the pipe's full, so don't need to write anything */
 			/* isserver is just a random byte to write */
-			if (write(ses.signal_pipe[1], &ses.isserver, 1) == 1 || errno == EAGAIN) {
+			if (write(ses.signal_pipe[1], &ses.isserver, 1) == 1 
+					|| errno == EAGAIN) {
 				break;
 			}
 			if (errno == EINTR) {
@@ -142,7 +146,6 @@
 }
 
 /* send the exit status or the signal causing termination for a session */
-/* XXX server */
 static void send_exitsignalstatus(struct Channel *channel) {
 
 	struct ChanSess *chansess = (struct ChanSess*)channel->typedata;
@@ -181,10 +184,11 @@
 
 	int i;
 	char* signame = NULL;
-
 	dropbear_assert(chansess->exit.exitpid != -1);
 	dropbear_assert(chansess->exit.exitsignal > 0);
 
+	TRACE(("send_msg_chansess_exitsignal %d", chansess->exit.exitsignal))
+
 	CHECKCLEARTOWRITE();
 
 	/* we check that we can match a signal name, otherwise
@@ -294,7 +298,7 @@
 		if (svr_ses.childpids[i].chansess == chansess) {
 			dropbear_assert(svr_ses.childpids[i].pid > 0);
 			TRACE(("closing pid %d", svr_ses.childpids[i].pid))
-			TRACE(("exitpid = %d", chansess->exit.exitpid))
+			TRACE(("exitpid is %d", chansess->exit.exitpid))
 			svr_ses.childpids[i].pid = -1;
 			svr_ses.childpids[i].chansess = NULL;
 		}
@@ -682,22 +686,24 @@
 		/* parent */
 		TRACE(("continue noptycommand: parent"))
 		chansess->pid = pid;
+		TRACE(("child pid is %d", pid))
 
 		addchildpid(chansess, pid);
 
 		if (svr_ses.lastexit.exitpid != -1) {
+			TRACE(("parent side: lastexitpid is %d", svr_ses.lastexit.exitpid))
 			/* The child probably exited and the signal handler triggered
 			 * possibly before we got around to adding the childpid. So we fill
-			 * out it's data manually */
+			 * out its data manually */
 			for (i = 0; i < svr_ses.childpidsize; i++) {
-				if (svr_ses.childpids[i].pid == pid) {
+				if (svr_ses.childpids[i].pid == svr_ses.lastexit.exitpid) {
+					TRACE(("found match for lastexitpid"))
 					svr_ses.childpids[i].chansess->exit = svr_ses.lastexit;
 					svr_ses.lastexit.exitpid = -1;
 				}
 			}
 		}
 
-
 		close(infds[FDIN]);
 		close(outfds[FDOUT]);
 		close(errfds[FDOUT]);