blob: 52c3bdba59e51e165e76813d51a1ec6c737509cc [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.
pub mod config;
use anyhow::{Context, Result};
use assembly_base_package::BasePackageBuilder;
use config::Config;
use ffx_assembly_args::ImageArgs;
use ffx_core::{ffx_bail, ffx_error};
use fuchsia_hash::Hash;
use fuchsia_merkle::MerkleTree;
use fuchsia_pkg::PackageManifest;
use std::fs::{File, OpenOptions};
use std::io::BufReader;
use std::path::{Path, PathBuf};
use zbi::ZbiBuilder;
pub fn assemble(args: ImageArgs) -> Result<()> {
let config = read_config(&args.config)?;
let base_package = construct_base_package(&args.gendir, &config)?;
let base_merkle = MerkleTree::from_reader(&base_package)
.context("Failed to calculate the base merkle")?
.root();
println!("Base merkle: {}", base_merkle);
let _zbi = construct_zbi(&args.gendir, &config, Some(base_merkle))?;
Ok(())
}
fn read_config(config_path: &String) -> Result<Config> {
let mut config = File::open(config_path)?;
let config = Config::from_reader(&mut config).context("Failed to read the image config")?;
println!("Config indicated version: {}", config.version);
Ok(config)
}
fn construct_base_package(gendir: &PathBuf, config: &Config) -> Result<File> {
let mut base_pkg_builder = BasePackageBuilder::default();
for pkg_manifest_path in &config.extra_packages_for_base_package {
let pkg_manifest = pkg_manifest_from_path(pkg_manifest_path);
base_pkg_builder.add_files_from_package(pkg_manifest);
}
for pkg_manifest_path in &config.base_packages {
let pkg_manifest = pkg_manifest_from_path(pkg_manifest_path);
base_pkg_builder.add_base_package(pkg_manifest);
}
for pkg_manifest_path in &config.cache_packages {
let pkg_manifest = pkg_manifest_from_path(pkg_manifest_path);
base_pkg_builder.add_cache_package(pkg_manifest);
}
let mut base_package = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open("base.far")
.or_else(|e| ffx_bail!("Failed to create the base package file: {}", e))?;
base_pkg_builder
.build(gendir, &mut base_package)
.or_else(|e| ffx_bail!("Failed to build the base package: {}", e))?;
println!("Base package: base.far");
Ok(base_package)
}
fn pkg_manifest_from_path(path: &str) -> PackageManifest {
let manifest_file = File::open(path).unwrap();
let pkg_manifest_reader = BufReader::new(manifest_file);
serde_json::from_reader(pkg_manifest_reader).unwrap()
}
fn construct_zbi(gendir: &PathBuf, config: &Config, base_merkle: Option<Hash>) -> Result<File> {
let mut zbi_builder = ZbiBuilder::default();
// Add the kernel image.
zbi_builder.set_kernel(&config.kernel_image);
// Instruct devmgr that a /system volume is required.
zbi_builder.add_boot_arg("devmgr.require-system=true");
// If a base merkle is supplied, then add the boot arguments for startup up pkgfs with the
// merkle of the Base Package.
if let Some(base_merkle) = base_merkle {
// Specify how to launch pkgfs: bin/pkgsvr <base-merkle>
zbi_builder.add_boot_arg(&format!("zircon.system.pkgfs.cmd=bin/pkgsvr+{}", base_merkle));
// Add the pkgfs blobs to the boot arguments, so that pkgfs can be bootstrapped out of blobfs,
// before the blobfs service is available.
let pkgfs_manifest: PackageManifest = config
.base_packages
.iter()
.map(String::as_str)
.map(pkg_manifest_from_path)
.find(|m| m.name() == "pkgfs")
.ok_or_else(|| ffx_error!("Failed to find pkgfs in the base packages"))?;
pkgfs_manifest.into_blobs().into_iter().filter(|b| b.path != "meta/").for_each(|b| {
zbi_builder.add_boot_arg(&format!("zircon.system.pkgfs.file.{}={}", b.path, b.merkle));
});
}
// Add the command line.
for cmd in &config.kernel_cmdline {
zbi_builder.add_cmdline_arg(cmd);
}
// Add the BootFS files.
for bootfs_entry in &config.bootfs_files {
zbi_builder.add_bootfs_file(&bootfs_entry.source, &bootfs_entry.destination);
}
// Build and return the ZBI.
zbi_builder.build(gendir, Path::new("myfuchsia.zbi"))?;
let zbi = OpenOptions::new()
.read(true)
.open("myfuchsia.zbi")
.or_else(|e| ffx_bail!("Failed to open the zbi: {}", e))?;
println!("ZBI: myfuchsia.zbi");
Ok(zbi)
}