// 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 "garnet/lib/process/process_builder.h"

#include <fcntl.h>
#include <lib/fdio/io.h>
#include <lib/fdio/limits.h>
#include <lib/fdio/namespace.h>
#include <lib/fdio/util.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <zircon/assert.h>
#include <zircon/dlfcn.h>
#include <zircon/process.h>
#include <zircon/processargs.h>
#include <zircon/syscalls.h>

#include <array>
#include <string_view>

#include "lib/svc/cpp/services.h"

namespace process {

namespace {

// This should match the values used by zircon/system/ulib/fdio/spawn.c
constexpr size_t kFdioResolvePrefixLen = 10;
const char kFdioResolvePrefix[kFdioResolvePrefixLen + 1] = "#!resolve ";

// It is possible to setup an infinite loop of resolvers. We want to avoid this
// being a common abuse vector, but also stay out of the way of any complex user
// setups. This value is the same as spawn.c's above.
constexpr int kFdioMaxResolveDepth = 256;

}  // namespace

ProcessBuilder::ProcessBuilder(std::shared_ptr<component::Services> services)
    : services_(services) {
  services_->ConnectToService(launcher_.NewRequest());
}

ProcessBuilder::ProcessBuilder(zx::job job,
                               std::shared_ptr<component::Services> services)
    : ProcessBuilder(services) {
  launch_info_.job = std::move(job);
}

ProcessBuilder::~ProcessBuilder() = default;

void ProcessBuilder::LoadVMO(zx::vmo executable) {
  launch_info_.executable = std::move(executable);
}

zx_status_t ProcessBuilder::LoadPath(const std::string& path) {
  int fd = open(path.c_str(), O_RDONLY);
  if (fd < 0)
    return ZX_ERR_IO;

  zx::vmo executable_vmo;
  zx_status_t status =
      fdio_get_vmo_clone(fd, executable_vmo.reset_and_get_address());
  close(fd);
  if (status != ZX_OK)
    return status;

  ::fidl::InterfaceHandle<::fuchsia::ldsvc::Loader> loader_iface;

  // Resolve VMOs containing #!resolve.
  fuchsia::process::ResolverSyncPtr resolver;  // Lazily bound.
  for (int i = 0; true; i++) {
    std::array<char, fuchsia::process::MAX_RESOLVE_NAME + kFdioResolvePrefixLen>
        head;
    head.fill(0);
    status = executable_vmo.read(head.data(), 0, head.size());
    if (status != ZX_OK)
      return status;
    if (memcmp(kFdioResolvePrefix, head.data(), kFdioResolvePrefixLen) != 0)
      break;  // No prefix match.

    if (i == kFdioMaxResolveDepth)
      return ZX_ERR_IO_INVALID;  // Too much nesting.

    // The process name is after the prefix until the first newline.
    std::string_view name(&head[kFdioResolvePrefixLen],
                          fuchsia::process::MAX_RESOLVE_NAME);
    if (auto newline_index = name.rfind('\n');
        newline_index != std::string_view::npos)
      name = name.substr(0, newline_index);

    // The resolver will give us a new VMO and loader to use.
    if (!resolver)
      services_->ConnectToService(resolver.NewRequest());
    resolver->Resolve(fidl::StringPtr(name.data(), name.size()), &status,
                      &executable_vmo, &loader_iface);
    if (status != ZX_OK)
      return status;
  }

  // Save the loader info.
  zx::handle loader = loader_iface.TakeChannel();
  if (!loader) {
    // Resolver didn't give us a specific one, clone ours.
    status = dl_clone_loader_service(loader.reset_and_get_address());
    if (status != ZX_OK)
      return status;
  }
  AddHandle(PA_LDSVC_LOADER, std::move(loader));

  // Save the VMO info. Name it with the file part of the path.
  launch_info_.executable = std::move(executable_vmo);
  const char* name = path.c_str();
  if (path.length() >= ZX_MAX_NAME_LEN) {
    size_t offset = path.rfind('/');
    if (offset != std::string::npos) {
      name += offset + 1;
    }
  }
  launch_info_.executable.set_property(ZX_PROP_NAME, name, strlen(name));

  return ZX_OK;
}

void ProcessBuilder::AddArgs(const std::vector<std::string>& argv) {
  if (argv.empty())
    return;
  if (launch_info_.name.empty())
    launch_info_.name = argv[0];
  fidl::VectorPtr<std::string> args;
  for (const auto& arg : argv)
    args.push_back(arg);
  launcher_->AddArgs(std::move(args));
}

void ProcessBuilder::AddHandle(uint32_t id, zx::handle handle) {
  handles_.push_back(fuchsia::process::HandleInfo{
      .id = id,
      .handle = std::move(handle),
  });
}

void ProcessBuilder::AddHandles(
    std::vector<fuchsia::process::HandleInfo> handles) {
  handles_.insert(handles_.end(), std::make_move_iterator(handles.begin()),
                   std::make_move_iterator(handles.end()));
}

void ProcessBuilder::SetDefaultJob(zx::job job) {
  handles_.push_back(fuchsia::process::HandleInfo{
      .id = PA_JOB_DEFAULT,
      .handle = std::move(job),
  });
}

void ProcessBuilder::SetName(std::string name) {
  launch_info_.name = std::move(name);
}

void ProcessBuilder::CloneJob() {
  zx::job duplicate_job;
  if (launch_info_.job)
    launch_info_.job.duplicate(ZX_RIGHT_SAME_RIGHTS, &duplicate_job);
  else
    zx::job::default_job()->duplicate(ZX_RIGHT_SAME_RIGHTS, &duplicate_job);
  SetDefaultJob(std::move(duplicate_job));
}

void ProcessBuilder::CloneNamespace() {
  fdio_flat_namespace_t* flat = nullptr;
  zx_status_t status = fdio_ns_export_root(&flat);
  if (status == ZX_OK) {
    std::vector<fuchsia::process::NameInfo> names;
    for (size_t i = 0; i < flat->count; ++i) {
      names.push_back(fuchsia::process::NameInfo{
          flat->path[i],
          fidl::InterfaceHandle<fuchsia::io::Directory>(
              zx::channel(flat->handle[i])),
      });
    }
    launcher_->AddNames(std::move(names));
  }
  free(flat);
}

void ProcessBuilder::CloneStdio() {
  // These file descriptors might be closed. Skip over erros cloning them.
  CloneFileDescriptor(STDIN_FILENO, STDIN_FILENO);
  CloneFileDescriptor(STDOUT_FILENO, STDOUT_FILENO);
  CloneFileDescriptor(STDERR_FILENO, STDERR_FILENO);
}

void ProcessBuilder::CloneEnvironment() {
  auto env = fidl::VectorPtr<std::string>::New(0);
  for (size_t i = 0; environ[i]; ++i)
    env.push_back(environ[i]);
  launcher_->AddEnvirons(std::move(env));
}

void ProcessBuilder::CloneAll() {
  CloneJob();
  CloneNamespace();
  CloneStdio();
  CloneEnvironment();
}

zx_status_t ProcessBuilder::CloneFileDescriptor(int local_fd, int target_fd) {
  zx_handle_t fdio_handles[FDIO_MAX_HANDLES];
  uint32_t fdio_types[FDIO_MAX_HANDLES];
  zx_status_t status =
      fdio_clone_fd(local_fd, target_fd, fdio_handles, fdio_types);
  if (status < ZX_OK)
    return status;
  for (int i = 0; i < status; ++i) {
    handles_.push_back(fuchsia::process::HandleInfo{
        .id = fdio_types[i],
        .handle = zx::handle(fdio_handles[i]),
    });
  }
  return ZX_OK;
}

zx_status_t ProcessBuilder::Prepare(std::string* error_message) {
  zx_status_t status = ZX_OK;
  launcher_->AddHandles(std::move(handles_));
  if (!launch_info_.job) {
    status = zx::job::default_job()->duplicate(ZX_RIGHT_SAME_RIGHTS,
                                               &launch_info_.job);
    if (status != ZX_OK)
      return status;
  }
  fuchsia::process::CreateWithoutStartingResult result;
  status = launcher_->CreateWithoutStarting(std::move(launch_info_), &result);
  if (status != ZX_OK)
    return status;
  if (result.status != ZX_OK) {
    if (error_message)
      *error_message = result.error_message;
    return result.status;
  }
  if (!result.data)
    return ZX_ERR_INVALID_ARGS;
  data_ = std::move(*result.data);
  return ZX_OK;
}

zx_status_t ProcessBuilder::Start(zx::process* process_out) {
  zx_status_t status =
      zx_process_start(data_.process.get(), data_.thread.get(), data_.entry,
                       data_.sp, data_.bootstrap.release(), data_.vdso_base);
  if (status == ZX_OK && process_out)
    *process_out = std::move(data_.process);
  return status;
}

}  // namespace process
