[ssh] spawn the shell with "system loader service"

In the future this is to be replaced by a shell runner, but for now, this
corrects an extant bug where the shell is being executed with libraries
sourced from the SSH package instead of from the shells native environment
(the boot/lib).

Change-Id: I401f0be4cc19b44c8e78331721a37de5f7934b8c
diff --git a/BUILD.gn b/BUILD.gn
index 7e07dd3..25bdab9 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -54,6 +54,7 @@
   ]
   public_deps = [
     "//zircon/public/lib/fdio",
+    "//zircon/public/lib/loader-service",
   ]
   configs += [ ":fuchsia" ]
 }
diff --git a/fuchsia/fuchsia-compat.c b/fuchsia/fuchsia-compat.c
index c397167..1a79e39 100644
--- a/fuchsia/fuchsia-compat.c
+++ b/fuchsia/fuchsia-compat.c
@@ -13,8 +13,10 @@
 #include <unistd.h>
 
 #include <lib/fdio/io.h>
-#include <lib/fdio/unsafe.h>
 #include <lib/fdio/spawn.h>
+#include <lib/fdio/unsafe.h>
+#include <loader-service/loader-service.h>
+#include <zircon/processargs.h>
 #include <zircon/status.h>
 #include <zircon/syscalls.h>
 #include <zircon/syscalls/port.h>
@@ -309,19 +311,41 @@
 		}
 	}
 
-	fdio_spawn_action_t actions[3] = {
-		{
-			.action = (in == out) ? FDIO_SPAWN_ACTION_CLONE_FD : FDIO_SPAWN_ACTION_TRANSFER_FD,
-			.fd = {.local_fd = in, .target_fd = STDIN_FILENO},
-		},
-		{
-			.action = (out == err) ? FDIO_SPAWN_ACTION_CLONE_FD : FDIO_SPAWN_ACTION_TRANSFER_FD,
-			.fd = {.local_fd = out, .target_fd = STDOUT_FILENO},
-		},
-		{
-			.action = FDIO_SPAWN_ACTION_TRANSFER_FD,
-			.fd = {.local_fd = err, .target_fd = STDERR_FILENO},
-		},
+	// TODO(CF-578): replace most of this with a "shell runner" instead
+	zx_status_t status;
+	loader_service_t *ldsvc;
+	if ((status = loader_service_create_fs(NULL, &ldsvc)) != ZX_OK) {
+		fprintf(stderr, "failed to create loader service: %s\n", zx_status_get_string(status));
+		exit(1);
+	}
+
+	zx_handle_t ldsvc_hnd;
+	if ((status = loader_service_connect(ldsvc, &ldsvc_hnd)) != ZX_OK) {
+		fprintf(stderr, "failed to connect to loader service: %s\n", zx_status_get_string(status));
+		loader_service_release(ldsvc);
+		exit(1);
+	}
+	loader_service_release(ldsvc);
+
+	fdio_spawn_action_t actions[4] = {
+			{
+				.action = FDIO_SPAWN_ACTION_ADD_HANDLE,
+				.h = {.id = PA_LDSVC_LOADER, .handle = ldsvc_hnd},
+			},
+			{
+					.action = (in == out) ? FDIO_SPAWN_ACTION_CLONE_FD
+																: FDIO_SPAWN_ACTION_TRANSFER_FD,
+					.fd = {.local_fd = in, .target_fd = STDIN_FILENO},
+			},
+			{
+					.action = (out == err) ? FDIO_SPAWN_ACTION_CLONE_FD
+																	: FDIO_SPAWN_ACTION_TRANSFER_FD,
+					.fd = {.local_fd = out, .target_fd = STDOUT_FILENO},
+			},
+			{
+					.action = FDIO_SPAWN_ACTION_TRANSFER_FD,
+					.fd = {.local_fd = err, .target_fd = STDERR_FILENO},
+			},
 	};
 
 	// TODO: set up environment
@@ -329,8 +353,8 @@
 	zx_handle_t proc = 0;
 	char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
 
-	uint32_t flags = FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_DEFAULT_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE;
-	zx_status_t status = fdio_spawn_etc(ZX_HANDLE_INVALID, flags, argv[0], argv, NULL, 3, actions, &proc, err_msg);
+	uint32_t flags = FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_NAMESPACE;
+	status = fdio_spawn_etc(ZX_HANDLE_INVALID, flags, argv[0], argv, NULL, 4, actions, &proc, err_msg);
 
 	if (status < 0) {
 		fprintf(stderr, "error from fdio_spawn_etc: %s\n", err_msg);