// Copyright 2019 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/storage/fshost/admin-server.h"

#include <fidl/fuchsia.device/cpp/wire.h>
#include <lib/async/default.h>
#include <lib/fdio/fd.h>
#include <lib/fidl-async/cpp/bind.h>
#include <lib/syslog/cpp/macros.h>

#include "src/lib/storage/fs_management/cpp/mount.h"
#include "src/lib/storage/vfs/cpp/service.h"
#include "src/storage/fshost/filesystem-mounter.h"

namespace fshost {

fbl::RefPtr<fs::Service> AdminServer::Create(FsManager* fs_manager, async_dispatcher* dispatcher) {
  return fbl::MakeRefCounted<fs::Service>(
      [dispatcher, fs_manager](fidl::ServerEnd<fuchsia_fshost::Admin> chan) {
        zx_status_t status = fidl::BindSingleInFlightOnly(
            dispatcher, std::move(chan), std::make_unique<AdminServer>(fs_manager));
        if (status != ZX_OK) {
          FX_LOGS(ERROR) << "failed to bind admin service: " << zx_status_get_string(status);
          return status;
        }
        return ZX_OK;
      });
}

void AdminServer::Shutdown(ShutdownRequestView request, ShutdownCompleter::Sync& completer) {
  FX_LOGS(INFO) << "received shutdown command over admin interface";
  fs_manager_->Shutdown([completer = completer.ToAsync()](zx_status_t status) mutable {
    if (status != ZX_OK) {
      FX_LOGS(ERROR) << "filesystem shutdown failed: " << zx_status_get_string(status);
      completer.Close(status);
    } else {
      FX_LOGS(INFO) << "shutdown complete";
      completer.Reply();
    }
  });
}

void AdminServer::Mount(MountRequestView request, MountCompleter::Sync& completer) {
  std::string device_path;
  if (auto result = fidl::WireCall(fidl::UnownedClientEnd<fuchsia_device::Controller>(
                                       request->device.channel().borrow()))
                        ->GetTopologicalPath();
      result.status() != ZX_OK) {
    FX_LOGS(WARNING) << "Unable to get device topological path (FIDL error): "
                     << zx_status_get_string(result.status());
  } else if (result->is_error()) {
    FX_LOGS(WARNING) << "Unable to get device topological path: "
                     << zx_status_get_string(result->error_value());
  } else {
    device_path = result->value()->path.get();
  }

  fbl::unique_fd fd;
  if (zx_status_t status =
          fdio_fd_create(request->device.TakeChannel().release(), fd.reset_and_get_address());
      status != ZX_OK) {
    completer.ReplyError(status);
    return;
  }
  fs_management::DiskFormat df = fs_management::DetectDiskFormat(fd.get());

  const std::string name(request->name.get());
  const auto& o = request->options;
  std::string compression_algorithm;
  if (o.has_write_compression_algorithm())
    compression_algorithm = o.write_compression_algorithm().get();
  fs_management::MountOptions options = {
      .readonly = o.has_read_only() && o.read_only(),
      .verbose_mount = o.has_verbose() && o.verbose(),
      .write_compression_algorithm =
          o.has_write_compression_algorithm() ? compression_algorithm.c_str() : nullptr,
  };

  FX_LOGS(INFO) << "Mounting " << fs_management::DiskFormatString(df) << " filesystem at /mnt/"
                << name;

  async_dispatcher_t* dispatcher = async_get_default_dispatcher();

  // Launching a filesystem requirees accessing the loader which is running on the same async loop
  // that we're running on but it's only running on one thread, so if we're not careful, we'll end
  // up with a deadlock.  To avoid this, spawn a separate thread.  Unfortunately, this isn't
  // thread-safe if we're shutting down, but since mounting is a debug only thing for now, we don't
  // worry about it.
  std::thread thread([device_path = std::move(device_path), name = std::move(name),
                      completer = completer.ToAsync(), options = std::move(options),
                      fd = std::move(fd), df = std::move(df), fs_manager = fs_manager_,
                      dispatcher]() mutable {
    static int mount_index = 0;
    std::string component_child_name = name + "." + std::to_string(mount_index++);
    options.component_child_name = component_child_name.c_str();
    options.component_collection_name = "fs-collection";
    auto mounted_filesystem_or =
        fs_management::Mount(std::move(fd), nullptr, df, options, fs_management::LaunchLogsAsync);
    if (mounted_filesystem_or.is_error()) {
      FX_LOGS(WARNING) << "Mount failed: " << mounted_filesystem_or.status_string();
      completer.ReplyError(mounted_filesystem_or.error_value());
      return;
    }

    // fs_manager isn't thread-safe, so we have to post back on to the async loop to attach the
    // mount.
    async::PostTask(
        dispatcher,
        [device_path = std::move(device_path),
         mounted_filesystem = std::move(*mounted_filesystem_or).TakeExportRoot(),
         name = std::move(name), fs_manager, completer = std::move(completer)]() mutable {
          if (zx_status_t status =
                  fs_manager->AttachMount(device_path, std::move(mounted_filesystem), name);
              status != ZX_OK) {
            FX_LOGS(WARNING) << "Failed to attach mount: " << zx_status_get_string(status);
            completer.ReplyError(status);
            return;
          }
          completer.ReplySuccess();
        });
  });

  thread.detach();
}

void AdminServer::Unmount(UnmountRequestView request, UnmountCompleter::Sync& completer) {
  FX_LOGS(INFO) << "Unmounting " << request->name.get();
  if (zx_status_t status = fs_manager_->DetachMount(request->name.get()); status != ZX_OK) {
    FX_LOGS(WARNING) << "Failed to unmount: " << zx_status_get_string(status);
    completer.ReplyError(status);
  } else {
    completer.ReplySuccess();
  }
}

void AdminServer::GetDevicePath(GetDevicePathRequestView request,
                                GetDevicePathCompleter::Sync& completer) {
  if (auto device_path_or = fs_manager_->GetDevicePath(request->fs_id); device_path_or.is_error()) {
    completer.ReplyError(device_path_or.status_value());
  } else {
    completer.ReplySuccess(fidl::StringView::FromExternal(*device_path_or));
  }
}

}  // namespace fshost
