// 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.

#include <fuchsia/sys/cpp/fidl.h>
#include <fuchsia/virtualization/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fdio/directory.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/syslog/cpp/log_settings.h>
#include <lib/syslog/cpp/macros.h>

#include <fs/pseudo_dir.h>
#include <fs/remote_dir.h>
#include <fs/synchronous_vfs.h>

#include "src/virtualization/lib/guest_config/guest_config.h"

namespace {

zx_status_t ReadGuestCfg(const fuchsia::io::DirectoryHandle& dir, const std::string& path,
                         fuchsia::virtualization::GuestConfig* cfg) {
  auto open_at = [&dir](const std::string& path, fidl::InterfaceRequest<fuchsia::io::File> file) {
    return fdio_open_at(dir.channel().get(), path.data(), fuchsia::io::OPEN_RIGHT_READABLE,
                        file.TakeChannel().release());
  };
  fuchsia::io::FileSyncPtr file;
  zx_status_t status = open_at(path.data(), file.NewRequest());
  if (status != ZX_OK) {
    return status;
  }
  zx_status_t buffer_status;
  std::unique_ptr<fuchsia::mem::Buffer> buffer;
  status = file->GetBuffer(fuchsia::io::VMO_FLAG_READ, &buffer_status, &buffer);
  if (status != ZX_OK) {
    return status;
  } else if (buffer_status != ZX_OK) {
    return buffer_status;
  }
  std::string str;
  str.resize(buffer->size);
  status = buffer->vmo.read(str.data(), 0, buffer->size);
  if (status != ZX_OK) {
    return status;
  }
  return guest_config::ParseConfig(str, std::move(open_at), cfg);
}

class ServiceProviderImpl : public fuchsia::sys::ServiceProvider,
                            public fuchsia::virtualization::GuestConfigProvider {
 public:
  static void CreateAndServe(fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> request,
                             fuchsia::io::DirectoryHandle pkg_dir,
                             fuchsia::io::DirectoryHandle svc_dir) {
    new ServiceProviderImpl(std::move(request), std::move(pkg_dir), std::move(svc_dir));
  }

 private:
  ServiceProviderImpl(fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> request,
                      fuchsia::io::DirectoryHandle pkg_dir, fuchsia::io::DirectoryHandle svc_dir)
      : service_provider_binding_(this, std::move(request)),
        pkg_dir_(std::move(pkg_dir)),
        svc_dir_(std::move(svc_dir)) {
    // The service provider will self-delete on disconnection.
    service_provider_binding_.set_error_handler([this](...) { delete this; });
  }

  // |fuchsia::sys::ServiceProvider|
  void ConnectToService(std::string service_name, zx::channel channel) override {
    if (service_name == fuchsia::virtualization::GuestConfigProvider::Name_) {
      fidl::InterfaceRequest<fuchsia::virtualization::GuestConfigProvider> request(
          std::move(channel));
      bindings_.AddBinding(this, std::move(request));
    }
  }

  // |fuchsia::virtualization::GuestConfigProvider|
  void Get(GetCallback callback) override {
    fuchsia::virtualization::GuestConfig cfg;
    // Read configuration provided by the component that launched us.
    fuchsia::virtualization::GuestConfigProviderSyncPtr provider;
    zx_status_t status = fdio_service_connect_at(
        svc_dir_.channel().get(), fuchsia::virtualization::GuestConfigProvider::Name_,
        provider.NewRequest().TakeChannel().release());
    if (status == ZX_OK) {
      // Get returns a status code, but failure is non-fatal, so ignore it.
      /* status = */ provider->Get(&cfg);
    }
    auto block_devices = std::move(*cfg.mutable_block_devices());
    // Read configuration from the guest's package.
    status = ReadGuestCfg(pkg_dir_, "data/guest.cfg", &cfg);
    if (status != ZX_OK) {
      FX_LOGS(WARNING) << "Failed to read guest configuration";
    }
    // Make sure that block devices provided by the configuration in the guest's
    // package take precedence, as the order matters.
    for (auto& block_device : block_devices) {
      cfg.mutable_block_devices()->emplace_back(std::move(block_device));
    }
    // Merge the command-line additions into the main kernel command-line field.
    for (auto& cmdline : *cfg.mutable_cmdline_add()) {
      cfg.mutable_cmdline()->append(" " + cmdline);
    }
    cfg.clear_cmdline_add();
    // Set any defaults, before returning the configuration.
    guest_config::SetDefaults(&cfg);
    callback(std::move(cfg));
  }

  fidl::Binding<fuchsia::sys::ServiceProvider> service_provider_binding_;
  fidl::BindingSet<fuchsia::virtualization::GuestConfigProvider> bindings_;
  fuchsia::io::DirectoryHandle pkg_dir_;
  fuchsia::io::DirectoryHandle svc_dir_;
};

class RunnerImpl : public fuchsia::sys::Runner {
 public:
  explicit RunnerImpl(async_dispatcher_t* dispatcher) : vfs_(dispatcher) {
    context_->svc()->Connect(launcher_.NewRequest());
    context_->outgoing()->AddPublicService(bindings_.GetHandler(this));
  }

 private:
  // |fuchsia::sys::Runner|
  void StartComponent(
      fuchsia::sys::Package application, fuchsia::sys::StartupInfo startup_info,
      fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller) override {
    fuchsia::sys::LaunchInfo launch_info;
    fuchsia::io::DirectoryHandle pkg_dir;
    fuchsia::io::DirectoryHandle svc_dir;

    // Create a bridge between directory_request that we got and VMM's
    // directory_request.
    fidl::InterfaceHandle<fuchsia::io::Directory> outgoing_dir;
    launch_info.directory_request = outgoing_dir.NewRequest().TakeChannel();
    fbl::RefPtr<fs::PseudoDir> dir = fbl::AdoptRef(new fs::PseudoDir());
    dir->AddEntry("svc", fbl::AdoptRef(new fs::RemoteDir(outgoing_dir.TakeChannel())));
    vfs_.ServeDirectory(std::move(dir), std::move(startup_info.launch_info.directory_request));

    // Pass-through some arguments directly to the VMM package.
    launch_info.url = "fuchsia-pkg://fuchsia.com/vmm#meta/vmm.cmx";
    launch_info.arguments = std::move(startup_info.launch_info.arguments);
    launch_info.flat_namespace = fuchsia::sys::FlatNamespace::New();
    for (size_t i = 0; i < startup_info.flat_namespace.paths.size(); ++i) {
      auto& path = startup_info.flat_namespace.paths[i];
      auto& directory = startup_info.flat_namespace.directories[i];
      if (path == "/pkg") {
        pkg_dir.set_channel(std::move(directory));
      } else if (path == "/svc") {
        svc_dir.set_channel(std::move(directory));
      }
    }

    // We list the GuestConfigProvider service, so that the VMM can connect back
    // to the guest runner in order to get its GuestConfig.
    auto service_list = fuchsia::sys::ServiceList::New();
    service_list->names.emplace_back(fuchsia::virtualization::GuestConfigProvider::Name_);
    ServiceProviderImpl::CreateAndServe(service_list->provider.NewRequest(), std::move(pkg_dir),
                                        std::move(svc_dir));
    launch_info.additional_services = std::move(service_list);

    launcher_->CreateComponent(std::move(launch_info), std::move(controller));
  }

  std::unique_ptr<sys::ComponentContext> context_ =
      sys::ComponentContext::CreateAndServeOutgoingDirectory();
  fuchsia::sys::LauncherPtr launcher_;
  fidl::BindingSet<fuchsia::sys::Runner> bindings_;
  fs::SynchronousVfs vfs_;
};

}  // namespace

int main(int argc, char** argv) {
  syslog::SetTags({"guest_runner"});
  async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
  RunnerImpl runner(loop.dispatcher());
  return loop.Run();
}
