summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2001-10-10 22:18:48 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2001-10-10 22:18:48 +0000
commitbcc3aa21e53af9f5221a902f16937a0a7eecbfb7 (patch)
tree6a82bafe9cc73e4886d2f5ced42a2764d0575880
parente4007be5e573a5e669e7746cdaddeaf11625cff0 (diff)
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 ?
-rw-r--r--usr.bin/ssh/channels.c49
-rw-r--r--usr.bin/ssh/channels.h4
-rw-r--r--usr.bin/ssh/clientloop.c3
-rw-r--r--usr.bin/ssh/nchan.c15
-rw-r--r--usr.bin/ssh/serverloop.c57
-rw-r--r--usr.bin/ssh/session.c29
-rw-r--r--usr.bin/ssh/session.h4
7 files changed, 83 insertions, 78 deletions
diff --git a/usr.bin/ssh/channels.c b/usr.bin/ssh/channels.c
index 4f7f33b685d..3e7ba4c7e28 100644
--- a/usr.bin/ssh/channels.c
+++ b/usr.bin/ssh/channels.c
@@ -39,7 +39,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.139 2001/10/09 21:59:41 markus Exp $");
+RCSID("$OpenBSD: channels.c,v 1.140 2001/10/10 22:18:47 markus Exp $");
#include "ssh.h"
#include "ssh1.h"
@@ -331,10 +331,6 @@ channel_free(Channel *c)
debug3("channel_free: status: %s", s);
xfree(s);
- if (c->detach_user != NULL) {
- debug("channel_free: channel %d: detaching channel user", c->self);
- c->detach_user(c->self, NULL);
- }
if (c->sock != -1)
shutdown(c->sock, SHUT_RDWR);
channel_close_fds(c);
@@ -1520,6 +1516,28 @@ channel_handler_init(void)
channel_handler_init_15();
}
+/* gc dead channels */
+static void
+channel_garbage_collect(Channel *c)
+{
+ if (c == NULL)
+ return;
+ if (c->detach_user != NULL) {
+ if (!chan_is_dead(c, 0))
+ return;
+ debug("channel %d: gc: notify user", c->self);
+ c->detach_user(c->self, NULL);
+ /* if we still have a callback */
+ if (c->detach_user != NULL)
+ return;
+ debug("channel %d: gc: user detached", c->self);
+ }
+ if (!chan_is_dead(c, 1))
+ return;
+ debug("channel %d: garbage collecting", c->self);
+ channel_free(c);
+}
+
static void
channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset)
{
@@ -1537,24 +1555,7 @@ channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset)
continue;
if (ftab[c->type] != NULL)
(*ftab[c->type])(c, readset, writeset);
- if (chan_is_dead(c)) {
- /*
- * we have to remove the fd's from the select mask
- * before the channels are free'd and the fd's are
- * closed
- */
- if (c->wfd != -1)
- FD_CLR(c->wfd, writeset);
- if (c->rfd != -1)
- FD_CLR(c->rfd, readset);
- if (c->efd != -1) {
- if (c->extended_usage == CHAN_EXTENDED_READ)
- FD_CLR(c->efd, readset);
- if (c->extended_usage == CHAN_EXTENDED_WRITE)
- FD_CLR(c->efd, writeset);
- }
- channel_free(c);
- }
+ channel_garbage_collect(c);
}
}
@@ -1625,7 +1626,7 @@ channel_output_poll()
if (compat20 &&
(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) {
/* XXX is this true? */
- debug2("channel %d: no data after CLOSE", c->self);
+ debug3("channel %d: will not send data after close", c->self);
continue;
}
diff --git a/usr.bin/ssh/channels.h b/usr.bin/ssh/channels.h
index 090d2ca6e64..89e48009dd5 100644
--- a/usr.bin/ssh/channels.h
+++ b/usr.bin/ssh/channels.h
@@ -32,7 +32,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/* RCSID("$OpenBSD: channels.h,v 1.49 2001/10/09 21:59:41 markus Exp $"); */
+/* RCSID("$OpenBSD: channels.h,v 1.50 2001/10/10 22:18:47 markus Exp $"); */
#ifndef CHANNEL_H
#define CHANNEL_H
@@ -214,7 +214,7 @@ void auth_input_open_request(int, int, void *);
/* channel close */
-int chan_is_dead(Channel *);
+int chan_is_dead(Channel *, int);
void chan_mark_dead(Channel *);
void chan_init_iostates(Channel *);
void chan_init(void);
diff --git a/usr.bin/ssh/clientloop.c b/usr.bin/ssh/clientloop.c
index e6da67d51a0..43332d1f4a1 100644
--- a/usr.bin/ssh/clientloop.c
+++ b/usr.bin/ssh/clientloop.c
@@ -59,7 +59,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: clientloop.c,v 1.82 2001/09/17 20:52:47 markus Exp $");
+RCSID("$OpenBSD: clientloop.c,v 1.83 2001/10/10 22:18:47 markus Exp $");
#include "ssh.h"
#include "ssh1.h"
@@ -753,6 +753,7 @@ client_channel_closed(int id, void *arg)
if (id != session_ident)
error("client_channel_closed: id %d != session_ident %d",
id, session_ident);
+ channel_cancel_cleanup(id);
session_closed = 1;
if (in_raw_mode())
leave_raw_mode();
diff --git a/usr.bin/ssh/nchan.c b/usr.bin/ssh/nchan.c
index 1dd9eab4991..08f38b02e21 100644
--- a/usr.bin/ssh/nchan.c
+++ b/usr.bin/ssh/nchan.c
@@ -23,7 +23,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: nchan.c,v 1.31 2001/07/17 21:04:57 markus Exp $");
+RCSID("$OpenBSD: nchan.c,v 1.32 2001/10/10 22:18:47 markus Exp $");
#include "ssh1.h"
#include "ssh2.h"
@@ -432,7 +432,7 @@ chan_mark_dead(Channel *c)
}
int
-chan_is_dead(Channel *c)
+chan_is_dead(Channel *c, int send)
{
if (c->type == SSH_CHANNEL_ZOMBIE) {
debug("channel %d: zombie", c->self);
@@ -461,7 +461,16 @@ chan_is_dead(Channel *c)
"read": "write");
} else {
if (!(c->flags & CHAN_CLOSE_SENT)) {
- chan_send_close2(c);
+ if (send) {
+ chan_send_close2(c);
+ } else {
+ /* channel would be dead if we sent a close */
+ if (c->flags & CHAN_CLOSE_RCVD) {
+ debug("channel %d: almost dead",
+ c->self);
+ return 1;
+ }
+ }
}
if ((c->flags & CHAN_CLOSE_SENT) &&
(c->flags & CHAN_CLOSE_RCVD)) {
diff --git a/usr.bin/ssh/serverloop.c b/usr.bin/ssh/serverloop.c
index 94886dbadd1..5976d51df1e 100644
--- a/usr.bin/ssh/serverloop.c
+++ b/usr.bin/ssh/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 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
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 @@ retry_select:
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 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg)
/* 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 @@ server_loop2(Authctxt *authctxt)
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 @@ server_loop2(Authctxt *authctxt)
break;
process_output(writeset);
}
+ collect_children();
+
if (readset)
xfree(readset);
if (writeset)
@@ -723,13 +729,8 @@ server_loop2(Authctxt *authctxt)
/* free all channels, no more reads and writes */
channel_free_all();
- /* collect remaining dead children, XXX not necessary? */
- signal(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
diff --git a/usr.bin/ssh/session.c b/usr.bin/ssh/session.c
index fa68c391732..b1d49314249 100644
--- a/usr.bin/ssh/session.c
+++ b/usr.bin/ssh/session.c
@@ -33,7 +33,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.106 2001/10/09 21:59:41 markus Exp $");
+RCSID("$OpenBSD: session.c,v 1.107 2001/10/10 22:18:47 markus Exp $");
#include "ssh.h"
#include "ssh1.h"
@@ -1576,36 +1576,29 @@ session_close_by_channel(int id, void *arg)
{
Session *s = session_by_channel(id);
if (s == NULL) {
- debug("session_close_by_channel: no session for channel %d", id);
+ debug("session_close_by_channel: no session for id %d", id);
return;
}
- /* disconnect channel */
- channel_cancel_cleanup(s->chanid);
- s->chanid = -1;
-
- debug("session_close_by_channel: channel %d kill %d", id, s->pid);
+ debug("session_close_by_channel: channel %d child %d", id, s->pid);
if (s->pid != 0) {
- /* notify child */
- if (kill(s->pid, SIGHUP) < 0)
- error("session_close_by_channel: kill %d: %s",
- s->pid, strerror(errno));
+ /* delay detach */
+ debug("session_close_by_channel: channel %d: has child", id);
+ return;
}
+ /* detach by removing callback */
+ channel_cancel_cleanup(s->chanid);
+ s->chanid = -1;
session_close(s);
}
void
-session_close_all(void)
+session_destroy_all(void)
{
int i;
for(i = 0; i < MAX_SESSIONS; i++) {
Session *s = &sessions[i];
- if (s->used) {
- if (s->chanid != -1) {
- channel_cancel_cleanup(s->chanid);
- s->chanid = -1;
- }
+ if (s->used)
session_close(s);
- }
}
}
diff --git a/usr.bin/ssh/session.h b/usr.bin/ssh/session.h
index d2b0d936409..6d5b8e69922 100644
--- a/usr.bin/ssh/session.h
+++ b/usr.bin/ssh/session.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.h,v 1.12 2001/10/09 21:59:41 markus Exp $ */
+/* $OpenBSD: session.h,v 1.13 2001/10/10 22:18:47 markus Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -32,6 +32,6 @@ int session_open(Authctxt*, int);
void session_input_channel_req(int, void *);
void session_close_by_pid(pid_t, int);
void session_close_by_channel(int, void *);
-void session_close_all(void);
+void session_destroy_all(void);
#endif