- (djm) OpenBSD CVS Sync
   - markus@cvs.openbsd.org 2001/10/10 22:18:47
     [channels.c channels.h clientloop.c nchan.c serverloop.c]
     [session.c session.h]
     try to keep channels open until an exit-status message is sent.
     don't kill the login shells if the shells stdin/out/err is closed.
     this should now work:
     ssh -2n localhost 'exec > /dev/null 2>&1; sleep 10; exit 5'; echo ?
diff --git a/serverloop.c b/serverloop.c
index 8a82af5..983fe74 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -35,7 +35,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: serverloop.c,v 1.81 2001/10/09 21:59:41 markus Exp $");
+RCSID("$OpenBSD: serverloop.c,v 1.82 2001/10/10 22:18:47 markus Exp $");
 
 #include "xmalloc.h"
 #include "packet.h"
@@ -208,9 +208,6 @@
 		max_time_milliseconds = options.client_alive_interval * 1000;
 	}
 
-	/* When select fails we restart from here. */
-retry_select:
-
 	/* Allocate and update select() masks for channel descriptors. */
 	channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 0);
 
@@ -275,12 +272,11 @@
 	ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
 
 	if (ret == -1) {
+		memset(*readsetp, 0, *maxfdp);
+		memset(*writesetp, 0, *maxfdp);
 		if (errno != EINTR)
 			error("select: %.100s", strerror(errno));
-		else
-			goto retry_select;
-	}
-	if (ret == 0 && client_alive_scheduled)
+	} else if (ret == 0 && client_alive_scheduled)
 		client_alive_check();
 }
 
@@ -668,13 +664,30 @@
 	/* NOTREACHED */
 }
 
+static void
+collect_children(void)
+{
+	pid_t pid;
+	sigset_t oset, nset;
+	int status;
+
+	/* block SIGCHLD while we check for dead children */
+	sigemptyset(&nset);
+	sigaddset(&nset, SIGCHLD);
+	sigprocmask(SIG_BLOCK, &nset, &oset);
+	if (child_terminated) {
+		while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+			session_close_by_pid(pid, status);
+		child_terminated = 0;
+	}
+	sigprocmask(SIG_SETMASK, &oset, NULL);
+}
+
 void
 server_loop2(Authctxt *authctxt)
 {
 	fd_set *readset = NULL, *writeset = NULL;
-	int rekeying = 0, max_fd, status, nalloc = 0;
-	pid_t pid;
-	sigset_t oset, nset;
+	int rekeying = 0, max_fd, nalloc = 0;
 
 	debug("Entering interactive session for SSH2.");
 
@@ -698,16 +711,7 @@
 		wait_until_can_do_something(&readset, &writeset, &max_fd,
 		    &nalloc, 0);
 
-		/* block SIGCHLD while we check for dead children */
-		sigemptyset(&nset);
-		sigaddset(&nset, SIGCHLD);
-		sigprocmask(SIG_BLOCK, &nset, &oset);
-		if (child_terminated) {
-			while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
-				session_close_by_pid(pid, status);
-			child_terminated = 0;
-		}
-		sigprocmask(SIG_SETMASK, &oset, NULL);
+		collect_children();
 		if (!rekeying)
 			channel_after_select(readset, writeset);
 		process_input(readset);
@@ -715,6 +719,8 @@
 			break;
 		process_output(writeset);
 	}
+	collect_children();
+
 	if (readset)
 		xfree(readset);
 	if (writeset)
@@ -723,13 +729,8 @@
 	/* free all channels, no more reads and writes */
 	channel_free_all();
 
-	/* collect remaining dead children, XXX not necessary? */
-	mysignal(SIGCHLD, SIG_DFL);
-	while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
-		session_close_by_pid(pid, status);
-
-	/* close remaining sessions, e.g remove wtmp entries */
-	session_close_all();
+	/* free remaining sessions, e.g. remove wtmp entries */
+	session_destroy_all();
 }
 
 static void