The unified diff between revisions [6cb77934..] and [fc57c894..] is displayed below. It can also be downloaded as a raw diff.

This diff has been restricted to the following files: 'svr-chansession.c'

#
#
# patch "svr-chansession.c"
#  from [6f7eb125702d99eea286ab8fe36606f2f25928e0]
#    to [507d7fb29b5b0a8c412603048937d6cf61a54787]
#
============================================================
--- svr-chansession.c	6f7eb125702d99eea286ab8fe36606f2f25928e0
+++ svr-chansession.c	507d7fb29b5b0a8c412603048937d6cf61a54787
@@ -59,7 +59,6 @@ static void send_msg_chansess_exitsignal
 		struct ChanSess * chansess);
 static void send_msg_chansess_exitsignal(struct Channel * channel,
 		struct ChanSess * chansess);
-static int sesscheckclose(struct Channel *channel);
 static void get_termmodes(struct ChanSess *chansess);


@@ -68,7 +67,8 @@ static int sesscheckclose(struct Channel

 static int sesscheckclose(struct Channel *channel) {
 	struct ChanSess *chansess = (struct ChanSess*)channel->typedata;
-	return chansess->exit.exitpid >= 0;
+	TRACE(("sesscheckclose, pid is %d", chansess->exit.exitpid))
+	return chansess->exit.exitpid != -1;
 }

 /* Handler for childs exiting, store the state for return to the client */
@@ -89,12 +89,13 @@ static void sesssigchild_handler(int UNU

 	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;
 			}
@@ -103,6 +104,7 @@ static void sesssigchild_handler(int UNU
 		/* 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;
 		}

@@ -121,9 +123,18 @@ static void sesssigchild_handler(int UNU
 			/* we use this to determine how pid exited */
 			exit->exitsignal = -1;
 		}
+
+		/* Make sure that the main select() loop wakes up */
+		while (1) {
+			/* isserver is just a random byte to write. We can't do anything
+			about an error so should just ignore it */
+			if (write(ses.signal_pipe[1], &ses.isserver, 1) == 1
+					|| errno != EINTR) {
+				break;
+			}
+		}
 	}

-
 	sa_chld.sa_handler = sesssigchild_handler;
 	sa_chld.sa_flags = SA_NOCLDSTOP;
 	sigaction(SIGCHLD, &sa_chld, NULL);
@@ -131,7 +142,6 @@ static void sesssigchild_handler(int UNU
 }

 /* 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;
@@ -170,10 +180,11 @@ static void send_msg_chansess_exitsignal

 	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
@@ -245,16 +256,17 @@ static void closechansess(struct Channel
 	unsigned int i;
 	struct logininfo *li;

-	chansess = (struct ChanSess*)channel->typedata;
+	TRACE(("enter closechansess"))

-	send_exitsignalstatus(channel);
+	chansess = (struct ChanSess*)channel->typedata;

-	TRACE(("enter closechansess"))
 	if (chansess == NULL) {
 		TRACE(("leave closechansess: chansess == NULL"))
 		return;
 	}

+	send_exitsignalstatus(channel);
+
 	m_free(chansess->cmd);
 	m_free(chansess->term);

@@ -282,7 +294,7 @@ static void closechansess(struct Channel
 		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;
 		}
@@ -646,6 +658,12 @@ static int noptycommand(struct Channel *
 	if (!pid) {
 		/* child */

+		TRACE(("back to normal sigchld"))
+		/* Revert to normal sigchld handling */
+		if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) {
+			dropbear_exit("signal() error");
+		}
+
 		/* redirect stdin/stdout */
 #define FDIN 0
 #define FDOUT 1
@@ -670,22 +688,24 @@ static int noptycommand(struct Channel *
 		/* 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]);
@@ -741,6 +761,12 @@ static int ptycommand(struct Channel *ch
 	if (pid == 0) {
 		/* child */

+		TRACE(("back to normal sigchld"))
+		/* Revert to normal sigchld handling */
+		if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) {
+			dropbear_exit("signal() error");
+		}
+
 		/* redirect stdin/stdout/stderr */
 		close(chansess->master);