[dmctl] Convert dmctl to a FIDL interface Part of the removal of ioctl ZX-2827 #done Test: Booted a system through mexec, verified "dm" commands still worked. Change-Id: Icfe9e0c0336772455b87e5b59ce86fa24262ebec
diff --git a/system/core/devmgr/devmgr/coordinator.cpp b/system/core/devmgr/devmgr/coordinator.cpp index 6924d471..1855caa 100644 --- a/system/core/devmgr/devmgr/coordinator.cpp +++ b/system/core/devmgr/devmgr/coordinator.cpp
@@ -28,7 +28,6 @@ #include <lib/zx/socket.h> #include <zircon/assert.h> #include <zircon/boot/bootdata.h> -#include <zircon/device/dmctl.h> #include <zircon/processargs.h> #include <zircon/syscalls.h> #include <zircon/syscalls/policy.h>
diff --git a/system/core/devmgr/dmctl/dmctl.cpp b/system/core/devmgr/dmctl/dmctl.cpp index e01cd68..ec14623 100644 --- a/system/core/devmgr/dmctl/dmctl.cpp +++ b/system/core/devmgr/dmctl/dmctl.cpp
@@ -10,7 +10,8 @@ #include <ddk/driver.h> #include <ddktl/device.h> #include <fuchsia/device/manager/c/fidl.h> -#include <zircon/device/dmctl.h> +#include <lib/zx/socket.h> +#include <lib/zx/vmo.h> #include "../devhost/device-internal.h" @@ -19,7 +20,7 @@ namespace { class Dmctl; -using DmctlBase = ddk::Device<Dmctl, ddk::Ioctlable, ddk::Writable>; +using DmctlBase = ddk::Device<Dmctl, ddk::Messageable, ddk::Writable>; class Dmctl : public DmctlBase { public: @@ -29,8 +30,7 @@ void DdkRelease(); zx_status_t DdkWrite(const void* buf, size_t count, zx_off_t off, size_t* actual); - zx_status_t DdkIoctl(uint32_t op, const void* in_buf, size_t in_len, void* out_buf, - size_t out_len, size_t* out_actual); + zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn); }; Dmctl::Dmctl(zx_device_t* parent) : DmctlBase(parent) { @@ -65,55 +65,48 @@ return ZX_OK; } -zx_status_t Dmctl::DdkIoctl(uint32_t op, const void* in_buf, size_t in_len, - void* out_buf, size_t out_len, size_t* out_actual) { - const zx::channel& rpc = *zxdev()->rpc; +static zx_status_t fidl_ExecuteCommand(void* ctx, zx_handle_t raw_log_socket, + const char* command_data, size_t command_size, fidl_txn_t* txn) { + zx::socket log_socket(raw_log_socket); + auto zxdev = static_cast<zx_device_t*>(ctx); + const zx::channel& rpc = *zxdev->rpc; + zx_status_t status, call_status; - switch (op) { - case IOCTL_DMCTL_COMMAND: { - if (in_len != sizeof(dmctl_cmd_t)) { - return ZX_ERR_INVALID_ARGS; - } + status = fuchsia_device_manager_CoordinatorDmCommand( + rpc.get(), log_socket.release(), command_data, command_size, + &call_status); + if (status == ZX_OK) { + status = call_status; + } + return fuchsia_device_manager_ExternalControllerExecuteCommand_reply(txn, status); +} - dmctl_cmd_t cmd; - memcpy(&cmd, in_buf, sizeof(cmd)); - cmd.name[sizeof(cmd.name) - 1] = 0; +static zx_status_t fidl_OpenVirtcon(void* ctx, zx_handle_t raw_vc_receiver) { + zx::channel vc_receiver(raw_vc_receiver); + auto zxdev = static_cast<zx_device_t*>(ctx); + const zx::channel& rpc = *zxdev->rpc; - status = fuchsia_device_manager_CoordinatorDmCommand( - rpc.get(), cmd.h, static_cast<const char*>(cmd.name), strlen(cmd.name), - &call_status); - if (status != ZX_OK) { - return status; - } else if (call_status != ZX_OK) { - // NOT_SUPPORTED tells the dispatcher to close the handle for - // ioctls that accept a handle argument, so we have to avoid - // returning that in this case where the handle has been passed - // to another process (and effectively closed) - if (call_status == ZX_ERR_NOT_SUPPORTED) { - call_status = ZX_ERR_INTERNAL; - } - return call_status; - } + return fuchsia_device_manager_CoordinatorDmOpenVirtcon(rpc.get(), vc_receiver.release()); +} - *out_actual = 0; - return ZX_OK; - } - case IOCTL_DMCTL_OPEN_VIRTCON: { - if (in_len != sizeof(zx_handle_t)) { - return ZX_ERR_INVALID_ARGS; - } - return fuchsia_device_manager_CoordinatorDmOpenVirtcon(rpc.get(), *(zx_handle_t*)in_buf); - } - case IOCTL_DMCTL_MEXEC: { - if (in_len != sizeof(dmctl_mexec_args_t)) { - return ZX_ERR_INVALID_ARGS; - } - auto args = reinterpret_cast<const dmctl_mexec_args_t*>(in_buf); - return fuchsia_device_manager_CoordinatorDmMexec(rpc.get(), args->kernel, args->bootdata); - } - default: - return ZX_ERR_INVALID_ARGS; - } +static zx_status_t fidl_PerformMexec(void* ctx, zx_handle_t raw_kernel, zx_handle_t raw_bootdata) { + zx::vmo kernel(raw_kernel); + zx::vmo bootdata(raw_bootdata); + auto zxdev = static_cast<zx_device_t*>(ctx); + const zx::channel& rpc = *zxdev->rpc; + + return fuchsia_device_manager_CoordinatorDmMexec(rpc.get(), kernel.release(), + bootdata.release()); +} + +static fuchsia_device_manager_ExternalController_ops_t fidl_ops = { + .ExecuteCommand = fidl_ExecuteCommand, + .OpenVirtcon = fidl_OpenVirtcon, + .PerformMexec = fidl_PerformMexec, +}; + +zx_status_t Dmctl::DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn) { + return fuchsia_device_manager_ExternalController_dispatch(zxdev(), txn, msg, &fidl_ops); } zx_driver_ops_t dmctl_driver_ops = []() {
diff --git a/system/core/netsvc/netboot.c b/system/core/netsvc/netboot.c index eed77d2..37e729e 100644 --- a/system/core/netsvc/netboot.c +++ b/system/core/netsvc/netboot.c
@@ -15,15 +15,14 @@ #include <threads.h> #include <unistd.h> +#include <fuchsia/device/manager/c/fidl.h> #include <inet6/inet6.h> #include <inet6/netifc.h> - -#include <zircon/process.h> -#include <zircon/processargs.h> -#include <zircon/syscalls.h> - +#include <lib/fdio/util.h> #include <zircon/boot/netboot.h> -#include <zircon/device/dmctl.h> +#include <zircon/processargs.h> +#include <zircon/process.h> +#include <zircon/syscalls.h> static uint32_t last_cookie = 0; static uint32_t last_cmd = 0; @@ -214,17 +213,17 @@ } static zx_status_t do_dmctl_mexec(void) { - dmctl_mexec_args_t args; + zx_handle_t kernel, bootdata; zx_status_t status = netboot_prepare_zbi(nbkernel.data, nbbootdata.data, - nbcmdline.file.data, nbcmdline.file.size, &args); + nbcmdline.file.data, nbcmdline.file.size, + &kernel, &bootdata); if (status != ZX_OK) { return status; } zx_handle_t wait_handle; - status = zx_handle_duplicate( - args.kernel, ZX_RIGHT_SAME_RIGHTS, &wait_handle); + status = zx_handle_duplicate(kernel, ZX_RIGHT_SAME_RIGHTS, &wait_handle); if (status != ZX_OK) { return status; } @@ -234,10 +233,16 @@ return ZX_ERR_INTERNAL; } - int r = ioctl_dmctl_mexec(fd, &args); - close(fd); - if (r < 0) { - return r; + zx_handle_t dmctl; + status = fdio_get_service_handle(fd, &dmctl); + if (status != ZX_OK) { + return status; + } + status = fuchsia_device_manager_ExternalControllerPerformMexec(dmctl, kernel, + bootdata); + zx_handle_close(dmctl); + if (status != ZX_OK) { + return status; } status = zx_object_wait_one(wait_handle, ZX_USER_SIGNAL_0,
diff --git a/system/core/netsvc/rules.mk b/system/core/netsvc/rules.mk index e438c9c..4fb52d8 100644 --- a/system/core/netsvc/rules.mk +++ b/system/core/netsvc/rules.mk
@@ -32,6 +32,8 @@ system/ulib/fdio \ system/ulib/zircon \ -MODULE_FIDL_LIBS := system/fidl/zircon-ethernet +MODULE_FIDL_LIBS := \ + system/fidl/fuchsia-device-manager \ + system/fidl/zircon-ethernet \ include make/module.mk
diff --git a/system/core/netsvc/zbi.cpp b/system/core/netsvc/zbi.cpp index 8230f03..6645dde 100644 --- a/system/core/netsvc/zbi.cpp +++ b/system/core/netsvc/zbi.cpp
@@ -11,7 +11,7 @@ zx_status_t netboot_prepare_zbi(zx_handle_t nbkernel_vmo, zx_handle_t nbbootdata_vmo, const uint8_t* cmdline, uint32_t cmdline_size, - dmctl_mexec_args_t* args) { + zx_handle_t* kernel_vmo, zx_handle_t* bootdata_vmo) { zbi::ZbiVMO kernel, data; if (nbkernel_vmo == ZX_HANDLE_INVALID) { @@ -64,7 +64,7 @@ printf("netbootloader: kernel ZBI %#x bytes data ZBI %#x bytes\n", kernel.Length(), data.Length()); - args->kernel = kernel.Release().release(); - args->bootdata = data.Release().release(); + *kernel_vmo = kernel.Release().release(); + *bootdata_vmo = data.Release().release(); return ZX_OK; }
diff --git a/system/core/netsvc/zbi.h b/system/core/netsvc/zbi.h index e60a39c..8826ade 100644 --- a/system/core/netsvc/zbi.h +++ b/system/core/netsvc/zbi.h
@@ -6,7 +6,6 @@ #include <stdint.h> #include <zircon/compiler.h> -#include <zircon/device/dmctl.h> #include <zircon/types.h> __BEGIN_CDECLS @@ -14,6 +13,6 @@ zx_status_t netboot_prepare_zbi(zx_handle_t nbkernel_vmo, zx_handle_t nbbootdata_vmo, const uint8_t* cmdline, uint32_t cmdline_size, - dmctl_mexec_args_t* args); + zx_handle_t* kernel, zx_handle_t* bootdata); __END_CDECLS
diff --git a/system/fidl/fuchsia-device-manager/coordinator.fidl b/system/fidl/fuchsia-device-manager/coordinator.fidl index 21050a4..68187ee 100644 --- a/system/fidl/fuchsia-device-manager/coordinator.fidl +++ b/system/fidl/fuchsia-device-manager/coordinator.fidl
@@ -4,6 +4,8 @@ library fuchsia.device.manager; +// TODO(teisenbe): Move these interfaces to be internal to the devmgr codebase + using zx; // This definition must be the same size as zx_device_prop_t and is checked by
diff --git a/system/fidl/fuchsia-device-manager/dmctl.fidl b/system/fidl/fuchsia-device-manager/dmctl.fidl new file mode 100644 index 0000000..0443cff --- /dev/null +++ b/system/fidl/fuchsia-device-manager/dmctl.fidl
@@ -0,0 +1,25 @@ +// Copyright 2018 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +library fuchsia.device.manager; + +using zx; + +/// Interface for requesting devmgr perform miscellaneous actions. +/// These methods are all work-arounds that should go away eventually. +[Layout = "Simple"] +interface ExternalController { + /// Execute the given string command. This is mostly used for accessing debug + /// interfaces, but also as a backdoor for plumbing that has not been fully + /// solved. + 1: ExecuteCommand(handle<socket>? log_socket, string:COMMAND_MAX? command) + -> (zx.status status); + + /// Opens a new virtual console and transfers a handle to it over |vc_receiver|. + 2: OpenVirtcon(handle<channel> vc_receiver); + + /// Perform an mexec with the given kernel and bootdata. + /// See ZX-2069 for the thoughts on deprecating mexec. + 3: PerformMexec(handle<vmo> kernel, handle<vmo> bootdata); +};
diff --git a/system/fidl/fuchsia-device-manager/rules.mk b/system/fidl/fuchsia-device-manager/rules.mk index a904bd5..a277ebf 100644 --- a/system/fidl/fuchsia-device-manager/rules.mk +++ b/system/fidl/fuchsia-device-manager/rules.mk
@@ -12,6 +12,8 @@ MODULE_FIDL_LIBRARY := fuchsia.device.manager -MODULE_SRCS += $(LOCAL_DIR)/coordinator.fidl +MODULE_SRCS += \ + $(LOCAL_DIR)/coordinator.fidl \ + $(LOCAL_DIR)/dmctl.fidl include make/module.mk
diff --git a/system/public/zircon/device/dmctl.h b/system/public/zircon/device/dmctl.h deleted file mode 100644 index d2879fc..0000000 --- a/system/public/zircon/device/dmctl.h +++ /dev/null
@@ -1,55 +0,0 @@ -// Copyright 2017 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#pragma once - -#include <stdint.h> -#include <zircon/device/ioctl.h> -#include <zircon/device/ioctl-wrapper.h> -#include <zircon/types.h> - -typedef struct { - zx_handle_t h; - char name[64]; -} dmctl_cmd_t; - -// Execute a dmctl command, returning output via provided -// socket handle. -#define IOCTL_DMCTL_COMMAND \ - IOCTL(IOCTL_KIND_SET_HANDLE, IOCTL_FAMILY_DMCTL, 1) - -// Open a new virtual console -// Pass a channel handle. -// On success one or two handles will be written back (a remoteio device) -// On failure the channel will be closed. -#define IOCTL_DMCTL_OPEN_VIRTCON \ - IOCTL(IOCTL_KIND_SET_HANDLE, IOCTL_FAMILY_DMCTL, 2) - -// Install a channel to receive updates on devices and drivers in the system -// This is an experimental, non-stable interface. Only one client is supported. -// Any later calls will disconnect earlier clients. -// One message will be sent on the provided channel per devmgr_event_t -#define IOCTL_DMCTL_WATCH_DEVMGR \ - IOCTL(IOCTL_KIND_SET_HANDLE, IOCTL_FAMILY_DMCTL, 3) - -typedef struct { - zx_handle_t kernel; - zx_handle_t bootdata; -} dmctl_mexec_args_t; - -// Soft reboot the system with a new kernel and bootdata. -// Passes a handle to the kernel vmo and a handle to the bootdata vmo. -// The bootdata vmo should contain the cmdline. -// If successful, this ioctl does not return. -#define IOCTL_DMCTL_MEXEC \ - IOCTL(IOCTL_KIND_SET_TWO_HANDLES, IOCTL_FAMILY_DMCTL, 4) - -// ssize_t ioctl_dmctl_command(int fd, dmctl_cmd_t* cmd); -IOCTL_WRAPPER_IN(ioctl_dmctl_command, IOCTL_DMCTL_COMMAND, dmctl_cmd_t); - -// ssize_t ioctl_dmctl_open_virtcon(int fd, zx_handle_t* h); -IOCTL_WRAPPER_IN(ioctl_dmctl_open_virtcon, IOCTL_DMCTL_OPEN_VIRTCON, zx_handle_t); - -// ssize_t ioctl_dmctl_mexec(int fd, dmctl_mexec_args_t* args); -IOCTL_WRAPPER_IN(ioctl_dmctl_mexec, IOCTL_DMCTL_MEXEC, dmctl_mexec_args_t);
diff --git a/system/uapp/run-vc/main.c b/system/uapp/run-vc/main.c index 2636b13..4e5b601 100644 --- a/system/uapp/run-vc/main.c +++ b/system/uapp/run-vc/main.c
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include <fcntl.h> +#include <fuchsia/device/manager/c/fidl.h> #include <lib/fdio/io.h> #include <lib/fdio/spawn.h> #include <lib/fdio/util.h> @@ -13,9 +14,8 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> -#include <zircon/device/dmctl.h> -#include <zircon/process.h> #include <zircon/processargs.h> +#include <zircon/process.h> #include <zircon/status.h> #include <zircon/syscalls.h> #include <zircon/types.h> @@ -30,15 +30,23 @@ return -1; } } + zx_handle_t dmctl; + zx_status_t status = fdio_get_service_handle(fd, &dmctl); + if (status != ZX_OK) { + fprintf(stderr, "error %s converting fd to handle\n", zx_status_get_string(status)); + return -1; + } zx_handle_t h0, h1; if (zx_channel_create(0, &h0, &h1) < 0) { return -1; } - if (ioctl_dmctl_open_virtcon(fd, &h1) < 0) { + + if (fuchsia_device_manager_ExternalControllerOpenVirtcon(dmctl, h1) < 0) { return -1; } - close(fd); + h1 = ZX_HANDLE_INVALID; + zx_handle_close(dmctl); zx_object_wait_one(h0, ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED, ZX_TIME_INFINITE, NULL); @@ -81,8 +89,8 @@ }; char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; - zx_status_t status = fdio_spawn_etc(ZX_HANDLE_INVALID, flags, argv[0], argv, - NULL, 1 + hcount, actions, NULL, err_msg); + status = fdio_spawn_etc(ZX_HANDLE_INVALID, flags, argv[0], argv, + NULL, 1 + hcount, actions, NULL, err_msg); if (status != ZX_OK) { fprintf(stderr, "error %d (%s) launching: %s\n", status, zx_status_get_string(status), err_msg);
diff --git a/system/uapp/run-vc/rules.mk b/system/uapp/run-vc/rules.mk index d6e852c..95e4c96 100644 --- a/system/uapp/run-vc/rules.mk +++ b/system/uapp/run-vc/rules.mk
@@ -17,4 +17,6 @@ system/ulib/zircon \ system/ulib/c +MODULE_FIDL_LIBS := system/fidl/fuchsia-device-manager + include make/module.mk
diff --git a/system/utest/kernel-unittests/kernel-unittests.cpp b/system/utest/kernel-unittests/kernel-unittests.cpp index 19c62a70..c8924a9 100644 --- a/system/utest/kernel-unittests/kernel-unittests.cpp +++ b/system/utest/kernel-unittests/kernel-unittests.cpp
@@ -5,10 +5,15 @@ #include <fcntl.h> #include <unistd.h> +#include <fuchsia/device/manager/c/fidl.h> +#include <lib/fdio/util.h> +#include <lib/zx/channel.h> +#include <lib/zx/socket.h> #include <unittest/unittest.h> -#include <zircon/device/dmctl.h> #include <zircon/syscalls.h> +namespace { + // Ask the kernel to run its unit tests. bool run_kernel_unittests() { BEGIN_TEST; @@ -18,23 +23,27 @@ // Send the command via devmgr. int dmctl_fd = open("/dev/misc/dmctl", O_WRONLY); ASSERT_GE(dmctl_fd, 0); - dmctl_cmd_t cmd; - ASSERT_LE(sizeof(command_string), sizeof(cmd.name)); - strcpy(cmd.name, command_string); - // devmgr's ioctl() requires us to pass a socket, but we don't read + + zx::channel dmctl; + ASSERT_EQ(fdio_get_service_handle(dmctl_fd, dmctl.reset_and_get_address()), ZX_OK); + + // dmctl's ExecuteCommand() requires us to pass a socket, but we don't read // from the other endpoint. - zx_handle_t handle; - ASSERT_EQ(zx_socket_create(0, &cmd.h, &handle), ZX_OK); - ssize_t result = ioctl_dmctl_command(dmctl_fd, &cmd); - ASSERT_EQ(close(dmctl_fd), 0); - ASSERT_EQ(zx_handle_close(handle), ZX_OK); + zx::socket local, remote; + ASSERT_EQ(zx::socket::create(0, &local, &remote), ZX_OK); + zx_status_t call_status; + zx_status_t status = fuchsia_device_manager_ExternalControllerExecuteCommand( + dmctl.get(), remote.release(), command_string, strlen(command_string), &call_status); // Check result of kernel unit tests. - ASSERT_EQ(result, ZX_OK); + ASSERT_EQ(status, ZX_OK); + ASSERT_EQ(call_status, ZX_OK); END_TEST; } +} // namespace + BEGIN_TEST_CASE(kernel_unittests) RUN_TEST(run_kernel_unittests) END_TEST_CASE(kernel_unittests)
diff --git a/system/utest/kernel-unittests/rules.mk b/system/utest/kernel-unittests/rules.mk index 090e22a..2ce7a8d 100644 --- a/system/utest/kernel-unittests/rules.mk +++ b/system/utest/kernel-unittests/rules.mk
@@ -13,10 +13,16 @@ MODULE_NAME := kernel-unittests +MODULE_STATIC_LIBS := \ + system/ulib/zx \ + MODULE_LIBS := \ system/ulib/c \ system/ulib/fdio \ system/ulib/unittest \ system/ulib/zircon \ +MODULE_FIDL_LIBS := \ + system/fidl/fuchsia-device-manager \ + include make/module.mk
diff --git a/third_party/uapp/dash/rules.mk b/third_party/uapp/dash/rules.mk index 5cdb0f2..7f3b589 100644 --- a/third_party/uapp/dash/rules.mk +++ b/third_party/uapp/dash/rules.mk
@@ -47,8 +47,17 @@ MODULE_NAME := sh -MODULE_STATIC_LIBS := system/ulib/pretty third_party/ulib/linenoise -MODULE_LIBS := system/ulib/fdio system/ulib/c system/ulib/zircon +MODULE_STATIC_LIBS := \ + system/ulib/pretty \ + third_party/ulib/linenoise \ + +MODULE_LIBS := \ + system/ulib/c \ + system/ulib/fdio \ + system/ulib/zircon + +MODULE_FIDL_LIBS := \ + system/fidl/fuchsia-device-manager \ MODULE_CFLAGS := -D_GNU_SOURCE -DBSD -DIFS_BROKEN -DJOBS=0 -DSHELL \ -DUSE_LINENOISE
diff --git a/third_party/uapp/dash/src/bltin/zircon.c b/third_party/uapp/dash/src/bltin/zircon.c index c9f30d2e..a7a6c457 100644 --- a/third_party/uapp/dash/src/bltin/zircon.c +++ b/third_party/uapp/dash/src/bltin/zircon.c
@@ -15,10 +15,10 @@ #include <sys/stat.h> #include <unistd.h> -#include <zircon/syscalls.h> +#include <fuchsia/device/manager/c/fidl.h> +#include <lib/fdio/util.h> #include <pretty/hexdump.h> - -#include <zircon/device/dmctl.h> +#include <zircon/syscalls.h> int zxc_dump(int argc, char** argv) { int fd; @@ -466,44 +466,40 @@ fprintf(stderr, "error: cannot open dmctl: %d\n", fd); return fd; } - - // commands with ':' get passed through and don't use - // socket for results (since there are none) - const char* p; - for (p = command; p < (command + length); p++) { - if (*p == ':') { - write(fd, command, length); - return 0; - } - } - - dmctl_cmd_t cmd; - if (length >= sizeof(cmd.name)) { - fprintf(stderr, "error: dmctl command longer than %zu bytes: '%.*s'\n", - sizeof(cmd.name), (int)length, command); - return -1; - } - snprintf(cmd.name, sizeof(cmd.name), command); - - zx_handle_t h; - if (zx_socket_create(0, &cmd.h, &h) < 0) { + zx_handle_t dmctl; + zx_status_t status = fdio_get_service_handle(fd, &dmctl); + if (status != ZX_OK) { return -1; } - int r = ioctl_dmctl_command(fd, &cmd); - close(fd); - if (r < 0) { - zx_handle_close(h); - return r; + if (length > fuchsia_device_manager_COMMAND_MAX) { + fprintf(stderr, "error: dmctl command longer than %u bytes: '%.*s'\n", + fuchsia_device_manager_COMMAND_MAX, (int)length, command); + return -1; + } + + zx_handle_t local, remote; + if (zx_socket_create(0, &remote, &local) != ZX_OK) { + zx_handle_close(dmctl); + return -1; + } + + zx_status_t call_status; + status = fuchsia_device_manager_ExternalControllerExecuteCommand(dmctl, remote, command, + length, &call_status); + remote = ZX_HANDLE_INVALID; + zx_handle_close(dmctl); + if (status != ZX_OK || call_status != ZX_OK) { + zx_handle_close(local); + return -1; } for (;;) { - zx_status_t status; char buf[32768]; size_t actual; - if ((status = zx_socket_read(h, 0, buf, sizeof(buf), &actual)) < 0) { + if ((status = zx_socket_read(local, 0, buf, sizeof(buf), &actual)) < 0) { if (status == ZX_ERR_SHOULD_WAIT) { - zx_object_wait_one(h, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, + zx_object_wait_one(local, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, ZX_TIME_INFINITE, NULL); continue; } @@ -519,7 +515,7 @@ } } } - zx_handle_close(h); + zx_handle_close(local); return 0; }