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

#include "filesystem-mounter.h"

#include <fuchsia/io/llcpp/fidl.h>
#include <fuchsia/update/verify/llcpp/fidl.h>
#include <lib/fdio/directory.h>
#include <lib/inspect/service/cpp/service.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/process.h>
#include <zircon/status.h>

#include <fbl/ref_ptr.h>

#include "fdio.h"
#include "fshost-fs-provider.h"
#include "pkgfs-launcher.h"
#include "src/storage/blobfs/mount.h"
#include "src/storage/minfs/minfs.h"

namespace devmgr {

namespace fio = llcpp::fuchsia::io;

zx_status_t FilesystemMounter::LaunchFs(int argc, const char** argv, zx_handle_t* hnd,
                                        uint32_t* ids, size_t len, uint32_t fs_flags) {
  FshostFsProvider fs_provider;
  DevmgrLauncher launcher(&fs_provider);
  return launcher.Launch(*zx::job::default_job(), argv[0], argv, nullptr, -1,
                         /* TODO(fxbug.dev/32044) */ zx::resource(), hnd, ids, len, nullptr,
                         fs_flags);
}

zx::status<zx::channel> FilesystemMounter::MountFilesystem(FsManager::MountPoint point,
                                                           const char* binary,
                                                           const mount_options_t& options,
                                                           zx::channel block_device_client,
                                                           uint32_t fs_flags) {
  zx::channel client, server;
  zx_status_t status = zx::channel::create(0, &client, &server);
  if (status != ZX_OK) {
    return zx::error(status);
  }

  size_t num_handles = 2;
  zx_handle_t handles[2] = {server.release(), block_device_client.release()};
  uint32_t ids[2] = {PA_DIRECTORY_REQUEST, FS_HANDLE_BLOCK_DEVICE_ID};

  fbl::Vector<const char*> argv;
  argv.push_back(binary);
  if (options.readonly) {
    argv.push_back("--readonly");
  }
  if (options.verbose_mount) {
    argv.push_back("--verbose");
  }
  if (options.collect_metrics) {
    argv.push_back("--metrics");
  }
  if (options.write_compression_algorithm != nullptr) {
    argv.push_back("--compression");
    argv.push_back(options.write_compression_algorithm);
  }
  if (options.sandbox_decompression) {
    argv.push_back("--sandbox_decompression");
  }
  if (options.cache_eviction_policy != nullptr) {
    argv.push_back("--eviction_policy");
    argv.push_back(options.cache_eviction_policy);
  }
  argv.push_back("mount");
  argv.push_back(nullptr);
  status =
      LaunchFs(static_cast<int>(argv.size() - 1), argv.data(), handles, ids, num_handles, fs_flags);
  if (status != ZX_OK) {
    return zx::error(status);
  }

  zx_signals_t observed = 0;
  status =
      client.wait_one(ZX_USER_SIGNAL_0 | ZX_CHANNEL_PEER_CLOSED, zx::time::infinite(), &observed);
  if ((status != ZX_OK) || (observed & ZX_CHANNEL_PEER_CLOSED)) {
    status = (status != ZX_OK) ? status : ZX_ERR_BAD_STATE;
    return zx::error(status);
  }

  zx::channel root;
  status = fs_root_handle(client.get(), root.reset_and_get_address());
  if (status != ZX_OK) {
    return zx::error(status);
  }
  status = InstallFs(point, std::move(root));
  if (status != ZX_OK) {
    return zx::error(status);
  }

  return zx::ok(std::move(client));
}

zx_status_t FilesystemMounter::MountData(zx::channel block_device, const mount_options_t& options) {
  if (data_mounted_) {
    return ZX_ERR_ALREADY_BOUND;
  }

  zx::status ret = MountFilesystem(FsManager::MountPoint::kData, "/pkg/bin/minfs", options,
                                   std::move(block_device), FS_SVC);
  if (ret.is_error()) {
    return ret.error_value();
  }

  data_mounted_ = true;
  return ZX_OK;
}

zx_status_t FilesystemMounter::MountInstall(zx::channel block_device,
                                            const mount_options_t& options) {
  if (install_mounted_) {
    return ZX_ERR_ALREADY_BOUND;
  }

  zx::status ret = MountFilesystem(FsManager::MountPoint::kInstall, "/pkg/bin/minfs", options,
                                   std::move(block_device), FS_SVC);
  if (ret.is_error()) {
    return ret.error_value();
  }

  install_mounted_ = true;
  return ZX_OK;
}

zx_status_t FilesystemMounter::MountFactoryFs(zx::channel block_device,
                                              const mount_options_t& options) {
  if (factory_mounted_) {
    return ZX_ERR_ALREADY_BOUND;
  }

  zx::status ret = MountFilesystem(FsManager::MountPoint::kFactory, "/pkg/bin/factoryfs", options,
                                   std::move(block_device), FS_SVC);
  if (ret.is_error()) {
    return ret.error_value();
  }

  factory_mounted_ = true;
  return ZX_OK;
}

zx_status_t FilesystemMounter::MountDurable(zx::channel block_device,
                                            const mount_options_t& options) {
  if (durable_mounted_) {
    return ZX_ERR_ALREADY_BOUND;
  }

  zx::status ret = MountFilesystem(FsManager::MountPoint::kDurable, "/pkg/bin/minfs", options,
                                   std::move(block_device), FS_SVC);
  if (ret.is_error()) {
    return ret.error_value();
  }

  durable_mounted_ = true;
  return ZX_OK;
}

zx_status_t FilesystemMounter::MountBlob(zx::channel block_device, const mount_options_t& options) {
  if (blob_mounted_) {
    return ZX_ERR_ALREADY_BOUND;
  }

  zx::channel fs_diagnostics_dir_client, fs_diagnostics_dir_server;
  zx_status_t status =
      zx::channel::create(0, &fs_diagnostics_dir_client, &fs_diagnostics_dir_server);
  if (status != ZX_OK) {
    FX_LOGS(ERROR) << "failed to create channel for diagnostics dir: "
                   << zx_status_get_string(status);
    return status;
  }

  zx::status ret = MountFilesystem(FsManager::MountPoint::kBlob, "/pkg/bin/blobfs", options,
                                   std::move(block_device), FS_SVC | FS_SVC_BLOBFS);
  if (ret.is_error()) {
    return ret.error_value();
  }
  status = fshost_.SetFsExportRoot(FsManager::MountPoint::kBlob, std::move(ret).value());
  if (status != ZX_OK) {
    return status;
  }

  status = fshost_.ForwardFsDiagnosticsDirectory(FsManager::MountPoint::kBlob, "blobfs");
  if (status != ZX_OK) {
    FX_LOGS(ERROR) << "failed to add diagnostic directory for blobfs: "
                   << zx_status_get_string(status);
  }
  status = fshost_.ForwardFsService(FsManager::MountPoint::kBlob,
                                    llcpp::fuchsia::update::verify::BlobfsVerifier::Name);
  if (status != ZX_OK) {
    FX_LOGS(ERROR) << "failed to forward BlobfsVerifier service for blobfs: "
                   << zx_status_get_string(status);
  }

  blob_mounted_ = true;
  return ZX_OK;
}

void FilesystemMounter::TryMountPkgfs() {
  // Pkgfs waits for the following to mount before initializing:
  //   - Blobfs. Pkgfs is launched from blobfs, so this is a hard requirement.
  //   - Minfs. Pkgfs and other components want minfs to exist, so although they
  //   could launch and query for it later, this synchronization point means that
  //   subsequent clients will no longer need to query.
  //
  // TODO(fxbug.dev/38621): In the future, this mechanism may be replaced with a feed-forward
  // design to the mounted filesystems.
  if (!pkgfs_mounted_ && blob_mounted_ && (data_mounted_ || !WaitForData())) {
    // Historically we don't retry if pkgfs fails to launch, which seems reasonable since the
    // cause of a launch failure is unlikely to be transient.
    // TODO(fxbug.dev/58363): fshost should handle failures to mount critical filesystems better.
    auto status = LaunchPkgfs(this);
    if (status.is_error()) {
      FX_LOGS(ERROR) << "failed to launch pkgfs: " << status.status_string();
    }
    pkgfs_mounted_ = true;
  }
}

}  // namespace devmgr
