summaryrefslogtreecommitdiffhomepage
path: root/svr-chansession.c
diff options
context:
space:
mode:
Diffstat (limited to 'svr-chansession.c')
-rw-r--r--svr-chansession.c78
1 files changed, 42 insertions, 36 deletions
diff --git a/svr-chansession.c b/svr-chansession.c
index 0e34350..f26a6da 100644
--- a/svr-chansession.c
+++ b/svr-chansession.c
@@ -80,72 +80,78 @@ static int sesscheckclose(const struct Channel *channel) {
return chansess->exit.exitpid != -1;
}
-/* Handler for childs exiting, store the state for return to the client */
-
-/* There's a particular race we have to watch out for: if the forked child
- * executes, exits, and this signal-handler is called, all before the parent
- * gets to run, then the childpids[] array won't have the pid in it. Hence we
- * use the svr_ses.lastexit struct to hold the exit, which is then compared by
- * the parent when it runs. This work correctly at least in the case of a
- * single shell spawned (ie the usual case) */
-static void sesssigchild_handler(int UNUSED(dummy)) {
-
+void svr_chansess_checksignal(void) {
int status;
pid_t pid;
- unsigned int i;
- struct sigaction sa_chld;
- struct exitinfo *exit = NULL;
- const int saved_errno = errno;
-
- /* Make channel handling code look for closed channels */
- ses.channel_signal_pending = 1;
+ if (!ses.channel_signal_pending) {
+ return;
+ }
- TRACE(("enter sigchld handler"))
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ unsigned int i;
+ struct exitinfo *ex = NULL;
TRACE(("sigchld handler: pid %d", pid))
- exit = NULL;
+ ex = 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;
+ ex = &svr_ses.childpids[i].chansess->exit;
break;
}
}
/* 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) {
+ if (ex == NULL) {
TRACE(("using lastexit"));
- exit = &svr_ses.lastexit;
+ ex = &svr_ses.lastexit;
}
- exit->exitpid = pid;
+ ex->exitpid = pid;
if (WIFEXITED(status)) {
- exit->exitstatus = WEXITSTATUS(status);
+ ex->exitstatus = WEXITSTATUS(status);
}
if (WIFSIGNALED(status)) {
- exit->exitsignal = WTERMSIG(status);
+ ex->exitsignal = WTERMSIG(status);
#if !defined(AIX) && defined(WCOREDUMP)
- exit->exitcore = WCOREDUMP(status);
+ ex->exitcore = WCOREDUMP(status);
#else
- exit->exitcore = 0;
+ ex->exitcore = 0;
#endif
} else {
/* we use this to determine how pid exited */
- exit->exitsignal = -1;
+ ex->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;
- }
+ }
+}
+
+/* Handler for childs exiting, store the state for return to the client */
+
+/* There's a particular race we have to watch out for: if the forked child
+ * executes, exits, and this signal-handler is called, all before the parent
+ * gets to run, then the childpids[] array won't have the pid in it. Hence we
+ * use the svr_ses.lastexit struct to hold the exit, which is then compared by
+ * the parent when it runs. This work correctly at least in the case of a
+ * single shell spawned (ie the usual case) */
+static void sesssigchild_handler(int UNUSED(dummy)) {
+ unsigned int i;
+ struct sigaction sa_chld;
+
+ const int saved_errno = errno;
+
+ TRACE(("enter sigchld handler"))
+
+ /* 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;
}
}