Fake enough of signal() and waitpid() to clean up children.
Change-Id: Idfdf268419b0b92c60d1e398bbfb0cda0cfa3036
diff --git a/fuchsia/README.md b/fuchsia/README.md
index aa1a6d7..06d8476 100644
--- a/fuchsia/README.md
+++ b/fuchsia/README.md
@@ -16,9 +16,10 @@
% netcp ~/.ssh/id_rsa.pub :/.ssh/authorized_keys
```
-Run `sshd` with `-d` for debug mode and `-r` to disable reexecing:
+Under `listen` run `sshd -ire` where `i` is for inetd mode, `r` to disable
+reexecing and `e` to print logs to stderr:
```
-$ sshd -dr
+$ listen 22 /system/bin/sshd -ire
```
### scp
diff --git a/fuchsia/fuchsia-compat.c b/fuchsia/fuchsia-compat.c
index efabdaa..e126723 100644
--- a/fuchsia/fuchsia-compat.c
+++ b/fuchsia/fuchsia-compat.c
@@ -3,12 +3,16 @@
// found in the LICENSE file.
#include <launchpad/launchpad.h>
+#include <magenta/syscalls.h>
+#include <pthread.h>
#include <pwd.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
-#include <unistd.h>
+
+#include "openbsd-compat/bsd-misc.h"
int chroot(const char *path) { return -1; }
@@ -43,7 +47,60 @@
#define ARGV_MAX 256
-mx_handle_t fuchsia_launch_child(const char *command, int in, int out, int err) {
+typedef struct {
+ enum {
+ UNUSED, RUNNING, STOPPED
+ } state;
+ mx_handle_t handle;
+ int exit_code;
+} Child;
+
+#define BASE_PID 2
+#define NUM_CHILDREN 256
+static Child children[NUM_CHILDREN];
+
+static Child* get_child(pid_t pid) {
+ assert(pid - BASE_PID < NUM_CHILDREN);
+ assert(pid >= BASE_PID);
+ return &children[pid - BASE_PID];
+}
+
+static pid_t get_unused_pid() {
+ for (int i=0; i<NUM_CHILDREN; i++) {
+ if (children[i].state == UNUSED) {
+ return i+BASE_PID;
+ }
+ }
+ fprintf(stderr, "Can't allocate new pid.\n");
+ exit(1);
+}
+
+static volatile mysig_t sigchld_handler = SIG_IGN;
+
+static void* wait_thread_func(void* voidp) {
+ Child* child = voidp;
+
+ mx_signals_t observed;
+ mx_object_wait_one(child->handle, MX_PROCESS_SIGNALED, MX_TIME_INFINITE, &observed);
+
+ mx_info_process_t info;
+ size_t actual;
+ mx_object_get_info(child->handle, MX_INFO_PROCESS, &info, sizeof(info), &actual, NULL);
+
+ child->state = STOPPED;
+ child->exit_code = info.return_code;
+
+ mysig_t handler = sigchld_handler;
+ if (handler == SIG_IGN || handler == SIG_DFL) {
+ // Don't call a handler
+ } else {
+ handler(SIGCHLD);
+ }
+
+ return NULL;
+}
+
+pid_t fuchsia_launch_child(const char *command, int in, int out, int err) {
const char *argv[ARGV_MAX];
int argc = 1;
argv[0] = "/boot/bin/sh";
@@ -70,8 +127,57 @@
mx_status_t status = launchpad_go(lp, &proc, &errmsg);
if (status < 0) {
- printf("error from launchpad_go: %s\n", errmsg);
+ fprintf(stderr, "error from launchpad_go: %s\n", errmsg);
+ exit(1);
}
- return proc;
+ pid_t pid = get_unused_pid();
+ Child* child = get_child(pid);
+ child->state = RUNNING;
+ child->handle = proc;
+
+ pthread_t wait_thread;
+ if (pthread_create(&wait_thread, NULL, wait_thread_func, (void*)child) != 0) {
+ fprintf(stderr, "Failed to create process waiter thread: %s\n", strerror(errno));
+ }
+
+ return pid;
+}
+
+mysig_t mysignal(int signum, mysig_t handler) {
+ if (signum == SIGCHLD) {
+ sigchld_handler = handler;
+ }
+ // Ignore all non-SIGCHLD requests
+ return handler;
+}
+
+pid_t waitpid(pid_t pid, int* status, int options) {
+ if (pid == -1 || pid == 0) {
+ // Find an exited process.
+ for (pid = BASE_PID; pid < BASE_PID + NUM_CHILDREN; pid++) {
+ if (get_child(pid)->state == STOPPED) {
+ return waitpid(pid, status, options);
+ }
+ }
+ if (options & WNOHANG) {
+ return 0;
+ } else {
+ fprintf(stderr, "No child pids waiting for wait.\n");
+ exit(1);
+ }
+ }
+
+ Child* child = get_child(pid);
+ if (child->state != STOPPED) {
+ fprintf(stderr, "Child with pid %d isn't stopped.\n", pid);
+ exit(1);
+ }
+
+ if (status) {
+ *status = child->exit_code;
+ }
+ child->state = UNUSED;
+
+ return pid;
}
diff --git a/fuchsia/fuchsia-compat.h b/fuchsia/fuchsia-compat.h
index a04794d..89a15fa 100644
--- a/fuchsia/fuchsia-compat.h
+++ b/fuchsia/fuchsia-compat.h
@@ -6,7 +6,7 @@
#include <magenta/types.h>
int chroot(const char *path);
-mx_handle_t fuchsia_launch_child(const char *command, int in, int out, int err);
+int fuchsia_launch_child(const char *command, int in, int out, int err);
#define CUSTOM_SYS_AUTH_PASSWD
diff --git a/fuchsia/sshd_config b/fuchsia/sshd_config
index 5b94765..5bf9825 100644
--- a/fuchsia/sshd_config
+++ b/fuchsia/sshd_config
@@ -88,7 +88,7 @@
#X11Forwarding no
#X11DisplayOffset 10
#X11UseLocalhost yes
-#PermitTTY yes
+PermitTTY no
#PrintMotd yes
#PrintLastLog yes
#TCPKeepAlive yes
diff --git a/openbsd-compat/bsd-misc.c b/openbsd-compat/bsd-misc.c
index 6f3bc8f..5a175cc 100644
--- a/openbsd-compat/bsd-misc.c
+++ b/openbsd-compat/bsd-misc.c
@@ -211,6 +211,7 @@
}
#endif /* HAVE_TCSENDBREAK */
+#ifndef __Fuchsia__
mysig_t
mysignal(int sig, mysig_t act)
{
@@ -237,6 +238,7 @@
return (signal(sig, act));
#endif
}
+#endif
#ifndef HAVE_STRDUP
char *
diff --git a/session.c b/session.c
index c51ede8..19b25f2 100644
--- a/session.c
+++ b/session.c
@@ -344,8 +344,8 @@
session_proctitle(s);
#ifdef __Fuchsia__
- mx_handle_t process_handle = fuchsia_launch_child(command, pin[0], pout[1], perr[1]);
- if (process_handle == 0) {
+ pid = fuchsia_launch_child(command, pin[0], pout[1], perr[1]);
+ if (pid <= 0) {
#ifdef USE_PIPES
close(pin[0]);
close(pin[1]);
@@ -361,8 +361,6 @@
#endif
return -1;
}
- // Force an mx_handle_t into a pid_t.
- pid = (pid_t)process_handle;
#else
/* Fork the child. */
switch ((pid = fork())) {
@@ -454,8 +452,10 @@
cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
#endif
- s->pid = pid;
#endif // __Fuchsia__
+
+ s->pid = pid;
+
/* Set interactive/non-interactive mode. */
packet_set_interactive(s->display != NULL,
options.ip_qos_interactive, options.ip_qos_bulk);