blob: 2ff0b848d6134d9cac72744e190ebe0a6508bdf3 [file] [log] [blame]
/*
* 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/commands/launch/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 {
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);
};