blob: 43121077643aca31fc1695f405593783f2bbaf6d [file] [log] [blame]
// Copyright 2021 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/developer/forensics/feedback/migration/utils/migrate.h"
#include <lib/syslog/cpp/macros.h>
#include <memory>
#include "lib/async/cpp/task.h"
#include "lib/fpromise/promise.h"
#include "lib/zx/time.h"
namespace forensics::feedback {
::fpromise::promise<std::tuple<::fpromise::result<void, Error>, ::fpromise::result<void, Error>,
::fpromise::result<void, Error>>>
MigrateData(async_dispatcher_t* dispatcher, const std::shared_ptr<sys::ServiceDirectory>& services,
const std::optional<MigrationLog>& migration_log, const zx::duration timeout) {
fbl::unique_fd data_fd(open("/data", O_DIRECTORY | O_RDWR, 0777));
if (!data_fd.is_valid()) {
FX_LOGS(ERROR) << "Unable to open /data";
}
fbl::unique_fd cache_fd(open("/cache", O_DIRECTORY | O_RDWR, 0777));
if (!cache_fd.is_valid()) {
FX_LOGS(ERROR) << "Unable to open /cache";
}
::fpromise::promise<void, Error> migrate_last_reboot_data =
::fpromise::make_result_promise<void, Error>(::fpromise::ok());
::fpromise::promise<void, Error> migrate_crash_reports_data =
::fpromise::make_result_promise<void, Error>(::fpromise::ok());
::fpromise::promise<void, Error> migrate_feedback_data_data =
::fpromise::make_result_promise<void, Error>(::fpromise::ok());
if (data_fd.is_valid() && cache_fd.is_valid() && migration_log) {
if (!migration_log->Contains(MigrationLog::Component::kLastReboot)) {
migrate_last_reboot_data =
MigrateLastRebootData(dispatcher, services, data_fd, cache_fd, timeout);
}
if (!migration_log->Contains(MigrationLog::Component::kCrashReports)) {
migrate_crash_reports_data =
MigrateCrashReportsData(dispatcher, services, data_fd, cache_fd, timeout);
}
if (!migration_log->Contains(MigrationLog::Component::kFeedbackData)) {
migrate_feedback_data_data =
MigrateFeedbackDataData(dispatcher, services, data_fd, cache_fd, timeout);
}
}
return ::fpromise::join_promises(std::move(migrate_last_reboot_data),
std::move(migrate_crash_reports_data),
std::move(migrate_feedback_data_data));
}
::fpromise::promise<void, Error> MigrateLastRebootData(
async_dispatcher_t* dispatcher, const std::shared_ptr<sys::ServiceDirectory>& services,
const fbl::unique_fd& data_fd, const fbl::unique_fd& cache_fd, const zx::duration timeout) {
auto last_reboot = std::make_shared<LastRebootDirectoryMigrator>(dispatcher);
if (services->Connect(last_reboot->NewRequest()) != ZX_OK) {
FX_LOGS(ERROR) << "Failed to connect to LastRebootDirectoryMigrator";
return ::fpromise::make_error_promise(Error::kConnectionError);
}
return last_reboot->GetDirectories(timeout).then(
// Duplicate the file descriptors and capture the Directory migrator pointer.
[data_fd = data_fd.duplicate(), cache_fd = cache_fd.duplicate(), last_reboot](
const ::fpromise::result<LastRebootDirectoryMigrator::Directories, Error>& result)
-> ::fpromise::result<void, Error> {
if (!result.is_ok()) {
FX_LOGS(ERROR) << "Failed to get directories from last reboot for migration: "
<< ToString(result.error());
return ::fpromise::error(result.error());
}
const auto& [old_data_fd, old_cache_fd] = result.value();
if (!Migrate(old_data_fd, data_fd)) {
FX_LOGS(ERROR) << "Failed to migrate last reboot's /data directory";
}
if (!Migrate(old_cache_fd, cache_fd)) {
FX_LOGS(ERROR) << "Failed to migrate last reboot's /cache directory";
}
FX_LOGS(INFO) << "Completed migrating last reboot";
return ::fpromise::ok();
});
}
::fpromise::promise<void, Error> MigrateCrashReportsData(
async_dispatcher_t* dispatcher, const std::shared_ptr<sys::ServiceDirectory>& services,
const fbl::unique_fd& data_fd, const fbl::unique_fd& cache_fd, zx::duration timeout) {
auto crash_reports = std::make_shared<CrashReportsDirectoryMigrator>(dispatcher);
if (services->Connect(crash_reports->NewRequest()) != ZX_OK) {
FX_LOGS(ERROR) << "Failed to connect to CrashReportsDirectoryMigrator";
return ::fpromise::make_error_promise(Error::kConnectionError);
}
return crash_reports->GetDirectories(timeout).then(
// Duplicate the file descriptors and capture the Directory migrator pointer.
[data_fd = data_fd.duplicate(), cache_fd = cache_fd.duplicate(), crash_reports](
const ::fpromise::result<CrashReportsDirectoryMigrator::Directories, Error>& result)
-> ::fpromise::result<void, Error> {
if (!result.is_ok()) {
FX_LOGS(ERROR) << "Failed to get directories from crash reports for migration: "
<< ToString(result.error());
return ::fpromise::error(result.error());
}
const auto& [old_data_fd, old_cache_fd] = result.value();
if (!Migrate(old_data_fd, data_fd)) {
FX_LOGS(ERROR) << "Failed to migrate crash reports' /data directory";
}
if (!Migrate(old_cache_fd, cache_fd)) {
FX_LOGS(ERROR) << "Failed to migrate crash reports' /cache directory";
}
FX_LOGS(INFO) << "Completed migrating crash reports";
return ::fpromise::ok();
});
}
::fpromise::promise<void, Error> MigrateFeedbackDataData(
async_dispatcher_t* dispatcher, const std::shared_ptr<sys::ServiceDirectory>& services,
const fbl::unique_fd& data_fd, const fbl::unique_fd& cache_fd, const zx::duration timeout) {
auto feedback_data = std::make_shared<FeedbackDataDirectoryMigrator>(dispatcher);
if (services->Connect(feedback_data->NewRequest()) != ZX_OK) {
FX_LOGS(ERROR) << "Failed to connect to FeedbackDataDirectoryMigrator";
return ::fpromise::make_error_promise(Error::kConnectionError);
}
return feedback_data->GetDirectories(timeout).then(
// Duplicate the file descriptors and capture the Directory migrator pointer.
[data_fd = data_fd.duplicate(), cache_fd = cache_fd.duplicate(), feedback_data](
const ::fpromise::result<FeedbackDataDirectoryMigrator::Directories, Error>& result)
-> ::fpromise::result<void, Error> {
if (!result.is_ok()) {
FX_LOGS(ERROR) << "Failed to get directories from feedback data for migration: "
<< ToString(result.error());
return ::fpromise::error(result.error());
}
const auto& [old_data_fd, old_cache_fd] = result.value();
if (!Migrate(old_data_fd, data_fd)) {
FX_LOGS(ERROR) << "Failed to migrate feedback data's /data directory";
}
if (!Migrate(old_cache_fd, cache_fd)) {
FX_LOGS(ERROR) << "Failed to migrate feedback data's /cache directory";
}
FX_LOGS(INFO) << "Completed migrating feedback data";
return ::fpromise::ok();
});
}
} // namespace forensics::feedback