blob: 384d1adcbd8f117605aa0297de3ded0017eeca0d [file] [log] [blame]
// Copyright 2020 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.
#include "src/bringup/bin/console-launcher/virtcon-setup.h"
#include <lib/fdio/directory.h>
#include <lib/fdio/io.h>
#include <lib/fdio/spawn.h>
#include <lib/zircon-internal/paths.h>
#include <zircon/processargs.h>
namespace console_launcher {
namespace {
// Start a shell with a given command.
// If `cmd` is null, then the shell is launched interactively.
zx::status<zx::channel> StartShell(const char* cmd) {
zx::channel local, remote;
zx_status_t status = zx::channel::create(0, &local, &remote);
if (status != ZX_OK) {
return zx::error(status);
}
const char* argv[] = {ZX_SHELL_DEFAULT, nullptr, nullptr, nullptr};
if (cmd) {
argv[1] = "-c";
argv[2] = cmd;
}
fdio_spawn_action_t actions[2] = {
{.action = FDIO_SPAWN_ACTION_SET_NAME, .name = {.data = "vc:sh"}},
{.action = FDIO_SPAWN_ACTION_ADD_HANDLE,
.h = {.id = PA_HND(PA_FD, FDIO_FLAG_USE_FOR_STDIO), .handle = remote.release()}},
};
uint32_t flags = FDIO_SPAWN_CLONE_ALL & ~FDIO_SPAWN_CLONE_STDIO;
char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
status = fdio_spawn_etc(ZX_HANDLE_INVALID, flags, argv[0], argv, nullptr, std::size(actions),
actions, nullptr, err_msg);
if (status != ZX_OK) {
printf("console-launcher: cannot spawn shell: %s: %d (%s)\n", err_msg, status,
zx_status_get_string(status));
return zx::error(status);
}
return zx::ok(std::move(local));
}
// Start a shell with a given command, and send it to virtcon.
// If `cmd` is null, then the shell is launched interactively.
zx_status_t StartVirtconShell(fidl::WireSyncClient<fuchsia_virtualconsole::SessionManager>& virtcon,
const char* cmd) {
auto result = StartShell(cmd);
if (!result.is_ok()) {
fprintf(stderr, "console-launcher: unable start virtcon shell: %s\n", result.status_string());
return result.status_value();
}
auto virtcon_result = virtcon.CreateSession(std::move(result.value()));
if (!virtcon_result.ok()) {
fprintf(stderr, "console-launcher: unable to create virtcon session: %d\n",
virtcon_result.status());
return virtcon_result.status();
}
if (virtcon_result->status != ZX_OK) {
fprintf(stderr, "console-launcher: unable to create virtcon session: %d\n",
virtcon_result->status);
return virtcon_result->status;
}
return ZX_OK;
}
} // namespace
zx::status<VirtconArgs> GetVirtconArgs(fidl::WireSyncClient<fuchsia_boot::Arguments>* boot_args) {
fuchsia_boot::wire::BoolPair bool_keys[]{
{fidl::StringView{"netsvc.disable"}, true},
{fidl::StringView{"netsvc.netboot"}, false},
{fidl::StringView{"devmgr.require-system"}, false},
};
auto bool_resp =
boot_args->GetBools(fidl::VectorView<fuchsia_boot::wire::BoolPair>::FromExternal(bool_keys));
if (!bool_resp.ok()) {
return zx::error(bool_resp.status());
}
const bool netsvc_disable = bool_resp->values[0];
const bool netsvc_netboot = bool_resp->values[1];
const bool require_system = bool_resp->values[2];
const bool netboot = !netsvc_disable && netsvc_netboot;
const bool should_launch = !require_system || netboot;
VirtconArgs args;
args.should_launch = should_launch;
args.need_debuglog = netboot;
return zx::ok(std::move(args));
}
zx_status_t SetupVirtconEtc(fidl::WireSyncClient<fuchsia_virtualconsole::SessionManager>& virtcon,
const VirtconArgs& args) {
if (!args.should_launch) {
return ZX_OK;
}
constexpr size_t kNumShells = 3;
for (size_t i = 0; i < kNumShells; i++) {
zx_status_t status;
if (args.need_debuglog && (i == 0)) {
status = StartVirtconShell(virtcon, "dlog -f -t");
} else {
status = StartVirtconShell(virtcon, nullptr);
}
if (status != ZX_OK) {
return status;
}
}
return ZX_OK;
}
zx_status_t SetupVirtcon(fidl::WireSyncClient<fuchsia_boot::Arguments>* boot_args) {
auto result = GetVirtconArgs(boot_args);
if (!result.is_ok()) {
return result.status_value();
}
VirtconArgs args = std::move(result.value());
if (!args.should_launch) {
return ZX_OK;
}
fidl::WireSyncClient<fuchsia_virtualconsole::SessionManager> virtcon;
{
zx::channel local, remote;
zx_status_t status = zx::channel::create(0, &local, &remote);
if (status != ZX_OK) {
return status;
}
status = fdio_service_connect("/svc/fuchsia.virtualconsole.SessionManager", remote.release());
if (status != ZX_OK) {
fprintf(stderr, "console-launcher: unable to connect to %s: %d\n",
fidl::DiscoverableProtocolName<fuchsia_virtualconsole::SessionManager>, status);
return status;
}
virtcon = fidl::WireSyncClient<fuchsia_virtualconsole::SessionManager>(std::move(local));
}
return SetupVirtconEtc(virtcon, args);
}
} // namespace console_launcher