| /* |
| * Copyright (C) 2019 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/libs/vm_manager/image_aggregator.h" |
| |
| #include <string> |
| #include <vector> |
| |
| #include <glog/logging.h> |
| #include <json/json.h> |
| |
| #include "common/libs/fs/shared_fd.h" |
| #include "common/libs/utils/files.h" |
| #include "common/libs/utils/subprocess.h" |
| #include "host/libs/config/cuttlefish_config.h" |
| |
| namespace vm_manager { |
| |
| namespace { |
| |
| const std::string BPTTOOL_FILE_PATH = "bin/cf_bpttool"; |
| |
| Json::Value bpttool_input(const std::vector<ImagePartition>& partitions) { |
| std::vector<off_t> file_sizes; |
| off_t total_size = 20 << 20; // 20 MB for padding |
| for (auto& partition : partitions) { |
| off_t partition_file_size = cvd::FileSize(partition.image_file_path); |
| if (partition_file_size == 0) { |
| LOG(FATAL) << "Expected partition file \"" << partition.image_file_path |
| << "\" but it was missing"; |
| } |
| total_size += partition_file_size; |
| file_sizes.push_back(partition_file_size); |
| } |
| Json::Value bpttool_input_json; |
| bpttool_input_json["settings"] = Json::Value(); |
| bpttool_input_json["settings"]["disk_size"] = (Json::Int64) total_size; |
| bpttool_input_json["partitions"] = Json::Value(Json::arrayValue); |
| for (size_t i = 0; i < partitions.size(); i++) { |
| Json::Value partition_json; |
| partition_json["label"] = partitions[i].label; |
| partition_json["size"] = (Json::Int64) file_sizes[i]; |
| partition_json["guid"] = "auto"; |
| partition_json["type_guid"] = "linux_fs"; |
| bpttool_input_json["partitions"].append(partition_json); |
| } |
| return bpttool_input_json; |
| } |
| |
| cvd::SharedFD json_to_fd(const Json::Value& json) { |
| Json::FastWriter json_writer; |
| std::string json_string = json_writer.write(json); |
| cvd::SharedFD pipe[2]; |
| cvd::SharedFD::Pipe(&pipe[0], &pipe[1]); |
| int written = pipe[1]->Write(json_string.c_str(), json_string.size()); |
| if (written < 0) { |
| LOG(FATAL) << "Failed to write to pipe, errno is " << pipe[0]->GetErrno(); |
| } else if (written < (int) json_string.size()) { |
| LOG(FATAL) << "Failed to write full json to pipe, only did " << written; |
| } |
| return pipe[0]; |
| } |
| |
| cvd::SharedFD bpttool_make_table(const cvd::SharedFD& input) { |
| auto bpttool_path = vsoc::DefaultHostArtifactsPath(BPTTOOL_FILE_PATH); |
| cvd::Command bpttool_cmd(bpttool_path); |
| bpttool_cmd.AddParameter("make_table"); |
| bpttool_cmd.AddParameter("--input=/dev/stdin"); |
| bpttool_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdIn, input); |
| bpttool_cmd.AddParameter("--output_json=/dev/stdout"); |
| cvd::SharedFD output_pipe[2]; |
| cvd::SharedFD::Pipe(&output_pipe[0], &output_pipe[1]); |
| bpttool_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdOut, output_pipe[1]); |
| int success = bpttool_cmd.Start().Wait(); |
| if (success != 0) { |
| LOG(FATAL) << "Unable to run bpttool. Exited with status " << success; |
| } |
| return output_pipe[0]; |
| } |
| |
| void bpttool_make_disk_image(const std::vector<ImagePartition>& partitions, |
| cvd::SharedFD table, const std::string& output) { |
| auto bpttool_path = vsoc::DefaultHostArtifactsPath(BPTTOOL_FILE_PATH); |
| cvd::Command bpttool_cmd(bpttool_path); |
| bpttool_cmd.AddParameter("make_disk_image"); |
| bpttool_cmd.AddParameter("--input=/dev/stdin"); |
| bpttool_cmd.AddParameter("--output=", cvd::AbsolutePath(output)); |
| bpttool_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdIn, table); |
| for (auto& partition : partitions) { |
| auto abs_path = cvd::AbsolutePath(partition.image_file_path); |
| bpttool_cmd.AddParameter("--image=" + partition.label + ":" + abs_path); |
| } |
| int success = bpttool_cmd.Start().Wait(); |
| if (success != 0) { |
| LOG(FATAL) << "Unable to run bpttool. Exited with status " << success; |
| } |
| } |
| |
| } // namespace |
| |
| void aggregate_image(const std::vector<ImagePartition>& partitions, |
| const std::string& output_path) { |
| auto bpttool_input_json = bpttool_input(partitions); |
| auto input_json_fd = json_to_fd(bpttool_input_json); |
| auto table_fd = bpttool_make_table(input_json_fd); |
| bpttool_make_disk_image(partitions, table_fd, output_path); |
| }; |
| |
| } // namespace vm_manager |