blob: c480d430a635f1dee37636b5e7c3bdc75417e664 [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "host/commands/snapshot_util_cvd/snapshot_taker.h"
#include <cstdlib>
#include <string>
#include <string_view>
#include <unordered_map>
#include <android-base/file.h>
#include <android-base/strings.h>
#include "common/libs/fs/shared_buf.h"
#include "common/libs/fs/shared_fd.h"
#include "common/libs/utils/environment.h"
#include "common/libs/utils/files.h"
#include "common/libs/utils/json.h"
#include "common/libs/utils/result.h"
#include "common/libs/utils/users.h"
#include "host/libs/command_util/snapshot_utils.h"
#include "host/libs/config/cuttlefish_config.h"
namespace cuttlefish {
/**
* cp -r <cuttlefish home dir> <snapshot_path>
* write meta info for cvd: i.e. HOME, group name, instance names
* returns the path of generated snapshot json file
*/
Result<std::string> HandleHostGroupSnapshot(const std::string& path) {
const auto cuttlefish_home = StringFromEnv("HOME", "");
CF_EXPECT(!cuttlefish_home.empty(),
"\"HOME\" environment variable must be set.");
const std::string snapshot_path = CF_EXPECT(EmulateAbsolutePath(InputPathForm{
.current_working_dir = CurrentDirectory(),
.home_dir = CF_EXPECT(SystemWideUserHome()),
.path_to_convert = path,
.follow_symlink = false,
}));
auto* cuttlefish_config = CuttlefishConfig::Get();
CF_EXPECT(cuttlefish_config != nullptr, "Cannot find cuttlefish_config.json");
const auto cuttlefish_root = cuttlefish_config->root_dir();
CF_EXPECTF(android::base::StartsWith(cuttlefish_root, cuttlefish_home),
"Cuttlefish Root directory \"{}\" "
"is not subdirectory of cuttlefish home \"{}\".",
cuttlefish_root, cuttlefish_home);
// cp -r HOME snapshot_path
auto always_true = [](const std::string&) -> bool { return true; };
CF_EXPECTF(CopyDirectoryRecursively(cuttlefish_root, snapshot_path,
/* verify_dest_dir_empty */ true,
/* predicate */ std::move(always_true)),
"\"cp -r {} {} failed.\"", cuttlefish_root, snapshot_path);
const auto meta_json =
CF_EXPECTF(CreateMetaInfo(*cuttlefish_config, snapshot_path),
"Failed to create ", kMetaInfoJsonFileName);
const auto serialized_meta_json = meta_json.toStyledString();
LOG(DEBUG) << "Generated " << kMetaInfoJsonFileName << ": " << std::endl
<< std::endl
<< serialized_meta_json;
// write meta_json to file
const auto meta_json_path = SnapshotMetaJsonPath(snapshot_path);
CF_EXPECTF(
android::base::WriteStringToFile(serialized_meta_json, meta_json_path,
/* follow_symlinks */ true),
"Failed to write the meta information in json to \"{}\"", meta_json_path);
// mkdir guest_snapshot under the snapshot directory
CF_EXPECT(meta_json.isMember(kGuestSnapshotField));
auto meta_json_guest_snapshot = meta_json[kGuestSnapshotField];
for (const auto& instance : cuttlefish_config->Instances()) {
CF_EXPECT(meta_json_guest_snapshot.isMember(instance.id()));
const std::string new_dir_path =
snapshot_path + "/" +
meta_json_guest_snapshot[instance.id()].asString();
CF_EXPECTF(EnsureDirectoryExists(new_dir_path),
"Failed to create instance guest snapshot directory {}",
new_dir_path);
}
return meta_json_path;
}
} // namespace cuttlefish