forked from brl/citadel-tools
Refactor multiple tools into a single binary.
citadel-tool now installed with a hardlink for each binary tool and dispatches on the exe path to the tool implementation. This makes the build faster, uses less disk space, and makes it easier to create new small tools.
This commit is contained in:
parent
dbdf0d4035
commit
2dc32d1f20
44
Cargo.lock
generated
44
Cargo.lock
generated
@ -95,37 +95,6 @@ dependencies = [
|
||||
"toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "citadel-image"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libcitadel 0.1.0",
|
||||
"serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "citadel-install"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libcitadel 0.1.0",
|
||||
"rpassword 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "citadel-mount"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libcitadel 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "citadel-realms"
|
||||
version = "0.1.0"
|
||||
@ -142,6 +111,19 @@ dependencies = [
|
||||
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "citadel-tool"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libcitadel 0.1.0",
|
||||
"rpassword 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.32.0"
|
||||
|
@ -1,2 +1,6 @@
|
||||
[workspace]
|
||||
members = ["citadel-desktopd", "citadel-image", "citadel-install", "citadel-mount", "citadel-realms"]
|
||||
members = ["citadel-desktopd", "citadel-realms", "citadel-tool" ]
|
||||
[profile.release]
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
incremental = false
|
||||
|
@ -1,12 +0,0 @@
|
||||
[package]
|
||||
name = "citadel-install"
|
||||
version = "0.1.0"
|
||||
authors = ["Bruce Leidl <bruce@subgraph.com>"]
|
||||
homepage = "http://github.com/subgraph/citadel"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libcitadel = { path = "../libcitadel" }
|
||||
failure = "0.1.3"
|
||||
libc = "0.2"
|
||||
rpassword = "2.1.0"
|
@ -1,10 +0,0 @@
|
||||
[package]
|
||||
name = "citadel-mount"
|
||||
version = "0.1.0"
|
||||
authors = ["Bruce Leidl <bruce@subgraph.com>"]
|
||||
homepage = "http://github.com/subgraph/citadel"
|
||||
|
||||
[dependencies]
|
||||
libcitadel = { path = "../libcitadel" }
|
||||
failure = "0.1.3"
|
||||
libc = "0.2"
|
@ -1,94 +0,0 @@
|
||||
#[macro_use] extern crate failure;
|
||||
#[macro_use] extern crate libcitadel;
|
||||
|
||||
use std::process::exit;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
|
||||
use libcitadel::{Result,CommandLine,set_verbose,format_error,ResourceImage,util};
|
||||
|
||||
|
||||
mod rootfs;
|
||||
|
||||
/// mount command supports 4 subcommands
|
||||
///
|
||||
/// citadel-mount rootfs
|
||||
/// citadel-mount kernel
|
||||
/// citadel-mount extra
|
||||
/// citadel-mount overlay
|
||||
///
|
||||
/// 'rootfs' creates the /dev/mapper/rootfs device which will be mounted as root filesystem
|
||||
///
|
||||
/// 'kernel' mounts a resource bundle containing kernel modules
|
||||
/// 'extra' mounts a resource bundle containing extra files
|
||||
/// 'overlay' mounts a tmpfs overlay over rootfs filesystem only if citadel.overlay is set
|
||||
///
|
||||
|
||||
fn main() {
|
||||
|
||||
if CommandLine::verbose() {
|
||||
set_verbose(true);
|
||||
}
|
||||
|
||||
let mut args = env::args();
|
||||
args.next();
|
||||
let result = match args.next() {
|
||||
Some(ref s) if s == "rootfs" => mount_rootfs(),
|
||||
Some(ref s) if s == "kernel" => mount_kernel(),
|
||||
Some(ref s) if s == "extra" => mount_extra(),
|
||||
Some(ref s) if s == "overlay" => mount_overlay(),
|
||||
_ => Err(format_err!("Bad or missing argument")),
|
||||
};
|
||||
|
||||
if let Err(ref e) = result {
|
||||
warn!("Failed: {}", format_error(e));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn mount_rootfs() -> Result<()> {
|
||||
info!("citadel-mount rootfs");
|
||||
rootfs::setup_rootfs()
|
||||
}
|
||||
|
||||
fn mount_kernel() -> Result<()> {
|
||||
info!("citadel-mount kernel");
|
||||
let mut image = ResourceImage::find("kernel")?;
|
||||
image.mount()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mount_extra() -> Result<()> {
|
||||
info!("citadel-mount extra");
|
||||
let mut image = ResourceImage::find("extra")?;
|
||||
image.mount()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mount_overlay() -> Result<()> {
|
||||
if !CommandLine::overlay() {
|
||||
info!("Not mounting rootfs overlay because citadel.overlay is not enabled");
|
||||
return Ok(())
|
||||
}
|
||||
info!("Creating rootfs overlay");
|
||||
|
||||
info!("Moving /sysroot mount to /rootfs.ro");
|
||||
fs::create_dir_all("/rootfs.ro")?;
|
||||
util::exec_cmdline("/usr/bin/mount", "--make-private /")?;
|
||||
util::exec_cmdline("/usr/bin/mount", "--move /sysroot /rootfs.ro")?;
|
||||
info!("Mounting tmpfs on /rootfs.rw");
|
||||
fs::create_dir_all("/rootfs.rw")?;
|
||||
util::exec_cmdline("/usr/bin/mount", "-t tmpfs -orw,noatime,mode=755 rootfs.rw /rootfs.rw")?;
|
||||
info!("Creating /rootfs.rw/work /rootfs.rw/upperdir");
|
||||
fs::create_dir_all("/rootfs.rw/upperdir")?;
|
||||
fs::create_dir_all("/rootfs.rw/work")?;
|
||||
info!("Mounting overlay on /sysroot");
|
||||
util::exec_cmdline("/usr/bin/mount", "-t overlay overlay -olowerdir=/rootfs.ro,upperdir=/rootfs.rw/upperdir,workdir=/rootfs.rw/work /sysroot")?;
|
||||
|
||||
info!("Moving /rootfs.ro and /rootfs.rw to new root");
|
||||
fs::create_dir_all("/sysroot/rootfs.ro")?;
|
||||
fs::create_dir_all("/sysroot/rootfs.rw")?;
|
||||
util::exec_cmdline("/usr/bin/mount", "--move /rootfs.ro /sysroot/rootfs.ro")?;
|
||||
util::exec_cmdline("/usr/bin/mount", "--move /rootfs.rw /sysroot/rootfs.rw")?;
|
||||
Ok(())
|
||||
}
|
@ -1,14 +1,14 @@
|
||||
[package]
|
||||
name = "citadel-image"
|
||||
name = "citadel-tool"
|
||||
version = "0.1.0"
|
||||
authors = ["Bruce Leidl <bruce@subgraph.com>"]
|
||||
homepage = "https://github.com/subgraph/citadel"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libcitadel = { path = "../libcitadel" }
|
||||
failure = "0.1"
|
||||
rpassword = "2.1.0"
|
||||
clap = "2.32.0"
|
||||
failure = "0.1.3"
|
||||
serde_derive = "1.0.82"
|
||||
serde = "1.0.82"
|
||||
toml = "0.4.10"
|
@ -1,8 +1,8 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::fs;
|
||||
|
||||
use crate::Result;
|
||||
use crate::util;
|
||||
use libcitadel::Result;
|
||||
use libcitadel::util;
|
||||
|
||||
///
|
||||
/// Represents a disk partition device on the system
|
@ -1,71 +1,43 @@
|
||||
#[macro_use] extern crate failure;
|
||||
|
||||
mod installer;
|
||||
mod cli;
|
||||
mod util;
|
||||
mod disks;
|
||||
|
||||
use std::result;
|
||||
use std::path::Path;
|
||||
use std::env;
|
||||
use std::time;
|
||||
use std::fs;
|
||||
use std::ffi::OsStr;
|
||||
use std::thread::{self,JoinHandle};
|
||||
use std::process::exit;
|
||||
use failure::Error;
|
||||
use std::time;
|
||||
use std::path::Path;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
|
||||
use libcitadel::Result;
|
||||
use libcitadel::util;
|
||||
use libcitadel::ResourceImage;
|
||||
use crate::boot::disks;
|
||||
use crate::boot::rootfs::setup_rootfs_resource;
|
||||
use crate::install::installer::Installer;
|
||||
|
||||
pub type Result<T> = result::Result<T,Error>;
|
||||
const IMAGE_DIRECTORY: &str = "/run/citadel/images";
|
||||
|
||||
fn main() {
|
||||
|
||||
let mut args = env::args();
|
||||
args.next();
|
||||
let result = match args.next() {
|
||||
Some(ref s) if s == "live-setup" => live_setup(),
|
||||
Some(ref s) if s == "copy-artifacts" => copy_artifacts(),
|
||||
Some(ref s) => cli_install_to(s),
|
||||
None => cli_install(),
|
||||
};
|
||||
|
||||
if let Err(ref e) = result {
|
||||
println!("Failed: {}", format_error(e));
|
||||
exit(1);
|
||||
}
|
||||
pub fn live_rootfs() -> Result<()> {
|
||||
copy_artifacts()?;
|
||||
let rootfs = find_rootfs_image()?;
|
||||
setup_rootfs_resource(&rootfs)
|
||||
}
|
||||
|
||||
pub fn format_error(err: &Error) -> String {
|
||||
let mut output = err.to_string();
|
||||
let mut prev = err.as_fail();
|
||||
while let Some(next) = prev.cause() {
|
||||
output.push_str(": ");
|
||||
output.push_str(&next.to_string());
|
||||
prev = next;
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
fn live_setup() -> Result<()> {
|
||||
if !Path::new("/etc/initrd-release").exists() {
|
||||
bail!("Not running in initramfs, cannot do live-setup");
|
||||
}
|
||||
let installer = installer::Installer::new_livesetup();
|
||||
installer.run()
|
||||
pub fn live_setup() -> Result<()> {
|
||||
decompress_images()?;
|
||||
let live = Installer::new_livesetup();
|
||||
live.run()
|
||||
}
|
||||
|
||||
fn copy_artifacts() -> Result<()> {
|
||||
|
||||
for _ in 0..3 {
|
||||
if try_copy_artifacts()? {
|
||||
decompress_images()?;
|
||||
//decompress_images()?;
|
||||
return Ok(())
|
||||
}
|
||||
// Try again after waiting for more devices to be discovered
|
||||
println!("Failed to find partition with images, trying again in 2 seconds");
|
||||
info!("Failed to find partition with images, trying again in 2 seconds");
|
||||
thread::sleep(time::Duration::from_secs(2));
|
||||
}
|
||||
Err(format_err!("Could not find partition containing resource images"))
|
||||
|
||||
}
|
||||
|
||||
fn try_copy_artifacts() -> Result<bool> {
|
||||
@ -89,22 +61,22 @@ fn try_copy_artifacts() -> Result<bool> {
|
||||
}
|
||||
|
||||
fn deploy_artifacts() -> Result<()> {
|
||||
let run_images = Path::new("/run/images");
|
||||
let run_images = Path::new(IMAGE_DIRECTORY);
|
||||
if !run_images.exists() {
|
||||
fs::create_dir_all(run_images)?;
|
||||
util::exec_cmdline("/bin/mount", "-t tmpfs -o size=4g images /run/images")?;
|
||||
util::exec_cmdline("/bin/mount", "-t tmpfs -o size=4g images /run/citadel/images")?;
|
||||
}
|
||||
|
||||
for entry in fs::read_dir("/boot/images")? {
|
||||
let entry = entry?;
|
||||
println!("Copying {:?} from /boot/images to /run/images", entry.file_name());
|
||||
println!("Copying {:?} from /boot/images to /run/citadel/images", entry.file_name());
|
||||
fs::copy(entry.path(), run_images.join(entry.file_name()))?;
|
||||
}
|
||||
println!("Copying bzImage to /run/images");
|
||||
fs::copy("/boot/bzImage", "/run/images/bzImage")?;
|
||||
println!("Copying bzImage to /run/citadel/images");
|
||||
fs::copy("/boot/bzImage", "/run/citadel/images/bzImage")?;
|
||||
|
||||
println!("Copying bootx64.efi to /run/images");
|
||||
fs::copy("/boot/EFI/BOOT/bootx64.efi", "/run/images/bootx64.efi")?;
|
||||
println!("Copying bootx64.efi to /run/citadel/images");
|
||||
fs::copy("/boot/EFI/BOOT/bootx64.efi", "/run/citadel/images/bootx64.efi")?;
|
||||
|
||||
deploy_syslinux_artifacts()?;
|
||||
|
||||
@ -119,9 +91,9 @@ fn deploy_syslinux_artifacts() -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!("Copying contents of /boot/syslinux to /run/images/syslinux");
|
||||
println!("Copying contents of /boot/syslinux to /run/citadel/images/syslinux");
|
||||
|
||||
let run_images_syslinux = Path::new("/run/images/syslinux");
|
||||
let run_images_syslinux = Path::new("/run/citadel/images/syslinux");
|
||||
fs::create_dir_all(run_images_syslinux)?;
|
||||
for entry in fs::read_dir(boot_syslinux)? {
|
||||
let entry = entry?;
|
||||
@ -134,17 +106,34 @@ fn deploy_syslinux_artifacts() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decompress_images() -> Result<()> {
|
||||
println!("decompressing images");
|
||||
let mut threads = Vec::new();
|
||||
for entry in fs::read_dir("/run/images")? {
|
||||
fn find_rootfs_image() -> Result<ResourceImage> {
|
||||
for entry in fs::read_dir(IMAGE_DIRECTORY)? {
|
||||
let entry = entry?;
|
||||
if entry.path().extension() == Some(OsStr::new("img")) {
|
||||
if let Ok(image) = ResourceImage::from_path(&entry.path()) {
|
||||
if image.metainfo().image_type() == "rootfs" {
|
||||
return Ok(image)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(format_err!("Unable to find rootfs resource image in {}", IMAGE_DIRECTORY))
|
||||
|
||||
}
|
||||
|
||||
fn decompress_images() -> Result<()> {
|
||||
println!("decompressing images");
|
||||
let mut threads = Vec::new();
|
||||
for entry in fs::read_dir("/run/citadel/images")? {
|
||||
let entry = entry?;
|
||||
if entry.path().extension() == Some(OsStr::new("img")) {
|
||||
if let Ok(image) = ResourceImage::from_path(&entry.path()) {
|
||||
if image.is_compressed() {
|
||||
threads.push(decompress_one_image(image));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for t in threads {
|
||||
t.join().unwrap()?;
|
||||
}
|
||||
@ -157,19 +146,3 @@ fn decompress_one_image(image: ResourceImage) -> JoinHandle<Result<()>> {
|
||||
image.decompress()
|
||||
})
|
||||
}
|
||||
|
||||
fn cli_install() -> Result<()> {
|
||||
let ok = cli::run_cli_install()?;
|
||||
if !ok {
|
||||
println!("Install cancelled...");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cli_install_to(target: &str) -> Result<()> {
|
||||
let ok = cli::run_cli_install_with(target)?;
|
||||
if !ok {
|
||||
println!("Install cancelled...");
|
||||
}
|
||||
Ok(())
|
||||
}
|
74
citadel-tool/src/boot/mod.rs
Normal file
74
citadel-tool/src/boot/mod.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use std::fs;
|
||||
use std::process::exit;
|
||||
|
||||
use libcitadel::{util,Result,ResourceImage,CommandLine,set_verbose,format_error};
|
||||
|
||||
mod live;
|
||||
mod disks;
|
||||
mod rootfs;
|
||||
|
||||
pub fn main(args: Vec<String>) {
|
||||
if CommandLine::verbose() {
|
||||
set_verbose(true);
|
||||
}
|
||||
|
||||
let command = args.iter().skip(1).next();
|
||||
|
||||
let result = match command {
|
||||
Some(s) if s == "rootfs" => do_rootfs(),
|
||||
Some(s) if s == "setup" => do_setup(),
|
||||
_ => Err(format_err!("Bad or missing argument")),
|
||||
};
|
||||
|
||||
if let Err(ref e) = result {
|
||||
warn!("Failed: {}", format_error(e));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn do_rootfs() -> Result<()> {
|
||||
if CommandLine::live_mode() || CommandLine::install_mode() {
|
||||
live::live_rootfs()
|
||||
} else {
|
||||
rootfs::setup_rootfs()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn do_setup() -> Result<()> {
|
||||
if CommandLine::live_mode() || CommandLine::install_mode() {
|
||||
live::live_setup()?;
|
||||
}
|
||||
|
||||
ResourceImage::mount_image_type("kernel")?;
|
||||
ResourceImage::mount_image_type("extra")?;
|
||||
|
||||
if CommandLine::overlay() {
|
||||
mount_overlay()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mount_overlay() -> Result<()> {
|
||||
info!("Creating rootfs overlay");
|
||||
|
||||
info!("Moving /sysroot mount to /rootfs.ro");
|
||||
fs::create_dir_all("/rootfs.ro")?;
|
||||
util::exec_cmdline("/usr/bin/mount", "--make-private /")?;
|
||||
util::exec_cmdline("/usr/bin/mount", "--move /sysroot /rootfs.ro")?;
|
||||
info!("Mounting tmpfs on /rootfs.rw");
|
||||
fs::create_dir_all("/rootfs.rw")?;
|
||||
util::exec_cmdline("/usr/bin/mount", "-t tmpfs -orw,noatime,mode=755 rootfs.rw /rootfs.rw")?;
|
||||
info!("Creating /rootfs.rw/work /rootfs.rw/upperdir");
|
||||
fs::create_dir_all("/rootfs.rw/upperdir")?;
|
||||
fs::create_dir_all("/rootfs.rw/work")?;
|
||||
info!("Mounting overlay on /sysroot");
|
||||
util::exec_cmdline("/usr/bin/mount", "-t overlay overlay -olowerdir=/rootfs.ro,upperdir=/rootfs.rw/upperdir,workdir=/rootfs.rw/work /sysroot")?;
|
||||
|
||||
info!("Moving /rootfs.ro and /rootfs.rw to new root");
|
||||
fs::create_dir_all("/sysroot/rootfs.ro")?;
|
||||
fs::create_dir_all("/sysroot/rootfs.rw")?;
|
||||
util::exec_cmdline("/usr/bin/mount", "--move /rootfs.ro /sysroot/rootfs.ro")?;
|
||||
util::exec_cmdline("/usr/bin/mount", "--move /rootfs.rw /sysroot/rootfs.rw")?;
|
||||
Ok(())
|
||||
}
|
@ -1,20 +1,11 @@
|
||||
use std::process::Command;
|
||||
|
||||
use libcitadel::{BlockDev,CommandLine,ImageHeader,Partition,Result,verity};
|
||||
use libcitadel::{BlockDev,ResourceImage,CommandLine,ImageHeader,Partition,Result,verity};
|
||||
use std::path::Path;
|
||||
use std::process::Stdio;
|
||||
use ResourceImage;
|
||||
|
||||
pub fn setup_rootfs() -> Result<()> {
|
||||
if CommandLine::install_mode() || CommandLine::live_mode() {
|
||||
setup_rootfs_resource()
|
||||
} else {
|
||||
let p = choose_boot_partiton(true)?;
|
||||
setup_partition(p)
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_partition(mut p: Partition) -> Result<()> {
|
||||
let mut p = choose_boot_partiton(true)?;
|
||||
if CommandLine::noverity() {
|
||||
setup_partition_unverified(&p)
|
||||
} else {
|
||||
@ -22,15 +13,11 @@ fn setup_partition(mut p: Partition) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_rootfs_resource() -> Result<()> {
|
||||
info!("Searching for rootfs resource image");
|
||||
|
||||
let img = ResourceImage::find_rootfs()?;
|
||||
|
||||
pub fn setup_rootfs_resource(rootfs: &ResourceImage) -> Result<()> {
|
||||
if CommandLine::noverity() {
|
||||
setup_resource_unverified(&img)
|
||||
setup_resource_unverified(&rootfs)
|
||||
} else {
|
||||
setup_resource_verified(&img)
|
||||
setup_resource_verified(&rootfs)
|
||||
}
|
||||
}
|
||||
|
@ -1,41 +1,29 @@
|
||||
#[macro_use] extern crate libcitadel;
|
||||
#[macro_use] extern crate failure;
|
||||
#[macro_use] extern crate serde_derive;
|
||||
|
||||
use std::process::exit;
|
||||
use std::path::Path;
|
||||
use std::fs;
|
||||
use std::process::exit;
|
||||
|
||||
use clap::{App,Arg,SubCommand,ArgMatches};
|
||||
use clap::AppSettings::*;
|
||||
|
||||
use crate::build::UpdateBuilder;
|
||||
use crate::config::BuildConfig;
|
||||
use libcitadel::{Result,ResourceImage,set_verbose,format_error,Partition,KeyPair,ImageHeader};
|
||||
use std::fs;
|
||||
|
||||
mod build;
|
||||
mod config;
|
||||
pub fn main(args: Vec<String>) {
|
||||
|
||||
fn main() {
|
||||
let app = App::new("citadel-image")
|
||||
.about("Citadel update image builder")
|
||||
.settings(&[ArgRequiredElseHelp,ColoredHelp, DisableHelpSubcommand, DisableVersion, DeriveDisplayOrder])
|
||||
|
||||
.subcommand(SubCommand::with_name("build")
|
||||
.about("Build an update image specified by a configuration file")
|
||||
.arg(Arg::with_name("build-file")
|
||||
.required(true)
|
||||
.help("Path to image build config file")))
|
||||
.subcommand(SubCommand::with_name("metainfo")
|
||||
.about("Display metainfo variables for an image file")
|
||||
.arg(Arg::with_name("path")
|
||||
.required(true)
|
||||
.help("Path to image file")))
|
||||
|
||||
.subcommand(SubCommand::with_name("generate-verity")
|
||||
.about("Generate dm-verity hash tree for an image file")
|
||||
.arg(Arg::with_name("path")
|
||||
.required(true)
|
||||
.help("Path to image file")))
|
||||
|
||||
.subcommand(SubCommand::with_name("verify")
|
||||
.about("Verify dm-verity hash tree for an image file")
|
||||
.arg(Arg::with_name("path")
|
||||
@ -76,10 +64,9 @@ fn main() {
|
||||
.help("Path to image file")));
|
||||
|
||||
set_verbose(true);
|
||||
let matches = app.get_matches();
|
||||
|
||||
let matches = app.get_matches_from(args);
|
||||
let result = match matches.subcommand() {
|
||||
("build", Some(m)) => build_image(m),
|
||||
("metainfo", Some(m)) => metainfo(m),
|
||||
("generate-verity", Some(m)) => generate_verity(m),
|
||||
("verify", Some(m)) => verify(m),
|
||||
@ -99,14 +86,6 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
fn build_image(arg_matches: &ArgMatches) -> Result<()> {
|
||||
let build_file = arg_matches.value_of("build-file").unwrap();
|
||||
let config = BuildConfig::load(build_file)?;
|
||||
let mut builder = UpdateBuilder::new(config);
|
||||
builder.build()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn metainfo(arg_matches: &ArgMatches) -> Result<()> {
|
||||
let img = load_image(arg_matches)?;
|
||||
print!("{}",String::from_utf8(img.header().metainfo_bytes())?);
|
@ -1,9 +1,9 @@
|
||||
use std::io::{self,Write};
|
||||
use std::path::Path;
|
||||
use crate::Result;
|
||||
use crate::util::Disk;
|
||||
use libcitadel::Result;
|
||||
use super::disk::Disk;
|
||||
use rpassword;
|
||||
use crate::installer::Installer;
|
||||
use crate::install::installer::Installer;
|
||||
|
||||
pub fn run_cli_install() -> Result<bool> {
|
||||
let disk = match choose_disk()? {
|
@ -1,58 +1,8 @@
|
||||
use std::mem;
|
||||
use std::ffi::CStr;
|
||||
use std::str::from_utf8_unchecked;
|
||||
use std::path::{Path,PathBuf};
|
||||
use std::process::{Command,ExitStatus,Stdio};
|
||||
use std::fs;
|
||||
|
||||
use libc::{self, c_char};
|
||||
use failure::ResultExt;
|
||||
use libcitadel::OsRelease;
|
||||
use libcitadel::Result;
|
||||
|
||||
use super::Result;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct UtsName(libc::utsname);
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl UtsName {
|
||||
pub fn sysname(&self) -> &str {
|
||||
to_str(&(&self.0.sysname as *const c_char ) as *const *const c_char)
|
||||
}
|
||||
|
||||
pub fn nodename(&self) -> &str {
|
||||
to_str(&(&self.0.nodename as *const c_char ) as *const *const c_char)
|
||||
}
|
||||
|
||||
pub fn release(&self) -> &str {
|
||||
to_str(&(&self.0.release as *const c_char ) as *const *const c_char)
|
||||
}
|
||||
|
||||
pub fn version(&self) -> &str {
|
||||
to_str(&(&self.0.version as *const c_char ) as *const *const c_char)
|
||||
}
|
||||
|
||||
pub fn machine(&self) -> &str {
|
||||
to_str(&(&self.0.machine as *const c_char ) as *const *const c_char)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uname() -> UtsName {
|
||||
unsafe {
|
||||
let mut ret: UtsName = mem::uninitialized();
|
||||
libc::uname(&mut ret.0);
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_str<'a>(s: *const *const c_char) -> &'a str {
|
||||
unsafe {
|
||||
let res = CStr::from_ptr(*s).to_bytes();
|
||||
from_utf8_unchecked(res)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Disk {
|
||||
@ -110,6 +60,7 @@ impl Disk {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn rootfs_channel() -> &'static str {
|
||||
match OsRelease::citadel_channel() {
|
||||
Some(channel) => channel,
|
||||
@ -154,3 +105,4 @@ fn check_cmd_status(cmd_path: &str, status: &ExitStatus) -> Result<()> {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
*/
|
@ -6,11 +6,10 @@ use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use std::time::Instant;
|
||||
|
||||
use libcitadel::util::{mount,exec_cmdline_with_output};
|
||||
use libcitadel::util::{self,mount,exec_cmdline_with_output};
|
||||
use libcitadel::RealmFS;
|
||||
|
||||
use super::util;
|
||||
use super::Result;
|
||||
use libcitadel::Result;
|
||||
use libcitadel::OsRelease;
|
||||
|
||||
const BLKDEACTIVATE: &str = "/sbin/blkdeactivate";
|
||||
const CRYPTSETUP: &str = "/sbin/cryptsetup";
|
||||
@ -40,7 +39,7 @@ const EXTRA_IMAGE_NAME: &str = "citadel-extra.img";
|
||||
const INSTALL_MOUNT: &str = "/run/installer/mnt";
|
||||
const LUKS_PASSPHRASE_FILE: &str = "/run/installer/luks-passphrase";
|
||||
|
||||
const DEFAULT_ARTIFACT_DIRECTORY: &str = "/run/images";
|
||||
const DEFAULT_ARTIFACT_DIRECTORY: &str = "/run/citadel/images";
|
||||
|
||||
const KERNEL_CMDLINE: &str = "add_efi_memmap intel_iommu=off cryptomgr.notests rcupdate.rcu_expedited=1 rcu_nocbs=0-64 tsc=reliable no_timer_check noreplace-smp i915.fastboot=1 quiet splash";
|
||||
|
||||
@ -183,15 +182,15 @@ impl Installer {
|
||||
}
|
||||
|
||||
fn setup_live_realm(&self) -> Result<()> {
|
||||
self.cmd(CITADEL_IMAGE, format!("decompress /run/images/base-realmfs.img"))?;
|
||||
self.cmd(CITADEL_IMAGE, format!("decompress /run/citadel/images/base-realmfs.img"))?;
|
||||
let realmfs_dir = self.storage().join("realms/realmfs-images");
|
||||
let base_realmfs = realmfs_dir.join("base-realmfs.img");
|
||||
|
||||
self.info(format!("creating directory {}", realmfs_dir.display()))?;
|
||||
fs::create_dir_all(&realmfs_dir)?;
|
||||
|
||||
self.info(format!("creating symlink {} -> {}", base_realmfs.display(), "/run/images/base-realmfs.img"))?;
|
||||
unixfs::symlink("/run/images/base-realmfs.img", &base_realmfs)?;
|
||||
self.info(format!("creating symlink {} -> {}", base_realmfs.display(), "/run/citadel/images/base-realmfs.img"))?;
|
||||
unixfs::symlink("/run/citadel/images/base-realmfs.img", &base_realmfs)?;
|
||||
self.mount_realmfs()?;
|
||||
|
||||
self.setup_storage()?;
|
||||
@ -201,7 +200,7 @@ impl Installer {
|
||||
fs::write(self.storage().join("realms/realm-main/config"), "realmfs = \"base\"")?;
|
||||
let rootfs = self.storage().join("realms/realm-main/rootfs");
|
||||
fs::remove_file(&rootfs)?;
|
||||
unixfs::symlink("/run/images/base-realmfs.mountpoint", &rootfs)?;
|
||||
unixfs::symlink("/run/citadel/images/base-realmfs.mountpoint", &rootfs)?;
|
||||
|
||||
self.info("Creating /Shared realms directory")?;
|
||||
fs::create_dir_all(self.storage().join("realms/Shared"))?;
|
||||
@ -211,12 +210,12 @@ impl Installer {
|
||||
}
|
||||
|
||||
pub fn mount_realmfs(&self) -> Result<()> {
|
||||
self.info("Creating loop device for /run/images/base-realmfs.img")?;
|
||||
let args = format!("--offset 4096 -f --show /run/images/base-realmfs.img");
|
||||
self.info("Creating loop device for /run/citadel/images/base-realmfs.img")?;
|
||||
let args = format!("--offset 4096 -f --show /run/citadel/images/base-realmfs.img");
|
||||
let loopdev = exec_cmdline_with_output("/sbin/losetup", args)?;
|
||||
self.info("Mounting image at /run/images/base-realmfs.mountpoint")?;
|
||||
fs::create_dir_all("/run/images/base-realmfs.mountpoint")?;
|
||||
mount(&loopdev, "/run/images/base-realmfs.mountpoint", Some("-oro"))?;
|
||||
self.info("Mounting image at /run/citadel/images/base-realmfs.mountpoint")?;
|
||||
fs::create_dir_all("/run/citadel/images/base-realmfs.mountpoint")?;
|
||||
mount(&loopdev, "/run/citadel/images/base-realmfs.mountpoint", Some("-oro"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -419,7 +418,7 @@ impl Installer {
|
||||
/*
|
||||
self.info("Creating rootfs symlink")?;
|
||||
unixfs::symlink(
|
||||
format!("/run/images/{}-realmfs.mountpoint", self.main_realmfs()),
|
||||
format!("/run/citadel/images/{}-realmfs.mountpoint", self.main_realmfs()),
|
||||
format!("{}/rootfs", realm.display()))?;
|
||||
*/
|
||||
|
||||
@ -430,7 +429,10 @@ impl Installer {
|
||||
}
|
||||
|
||||
fn setup_storage_resources(&self) -> Result<()> {
|
||||
let channel = util::rootfs_channel();
|
||||
let channel = match OsRelease::citadel_channel() {
|
||||
Some(channel) => channel,
|
||||
None => "dev",
|
||||
};
|
||||
let resources = self.storage().join("resources").join(channel);
|
||||
fs::create_dir_all(&resources)?;
|
||||
|
28
citadel-tool/src/install/mod.rs
Normal file
28
citadel-tool/src/install/mod.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use std::process::exit;
|
||||
|
||||
pub(crate) mod installer;
|
||||
mod cli;
|
||||
mod disk;
|
||||
|
||||
use libcitadel::format_error;
|
||||
|
||||
pub fn main(args: Vec<String>) {
|
||||
let mut args = args.iter().skip(1);
|
||||
let result = if let Some(dev) = args.next() {
|
||||
cli::run_cli_install_with(dev)
|
||||
} else {
|
||||
cli::run_cli_install()
|
||||
};
|
||||
|
||||
let ok = match result {
|
||||
Ok(ok) => ok,
|
||||
Err(ref err) => {
|
||||
println!("Install failed: {}", format_error(err));
|
||||
exit(1);
|
||||
},
|
||||
};
|
||||
if !ok {
|
||||
println!("Install cancelled...");
|
||||
}
|
||||
}
|
||||
|
58
citadel-tool/src/main.rs
Normal file
58
citadel-tool/src/main.rs
Normal file
@ -0,0 +1,58 @@
|
||||
#[macro_use] extern crate libcitadel;
|
||||
#[macro_use] extern crate failure;
|
||||
#[macro_use] extern crate serde_derive;
|
||||
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
use std::ffi::OsStr;
|
||||
use std::iter;
|
||||
|
||||
mod boot;
|
||||
mod image;
|
||||
mod install;
|
||||
mod mkimage;
|
||||
|
||||
fn main() {
|
||||
let exe = match env::current_exe() {
|
||||
Ok(path) => path,
|
||||
Err(_e) => {
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
let args = env::args().collect::<Vec<String>>();
|
||||
|
||||
if exe == Path::new("/usr/libexec/citadel-boot") {
|
||||
boot::main(args);
|
||||
} else if exe == Path::new("/usr/libexec/citadel-install") {
|
||||
install::main(args);
|
||||
} else if exe == Path::new("/usr/bin/citadel-image") {
|
||||
image::main(args);
|
||||
} else if exe.file_name() == Some(OsStr::new("citadel-mkimage")) {
|
||||
mkimage::main(args);
|
||||
} else if exe.file_name() == Some(OsStr::new("citadel-tool")) {
|
||||
dispatch_command(args);
|
||||
} else {
|
||||
println!("Error: unknown executable {}", exe.display());
|
||||
}
|
||||
}
|
||||
|
||||
fn dispatch_command(args: Vec<String>) {
|
||||
if let Some(command) = args.iter().skip(1).next() {
|
||||
match command.as_str() {
|
||||
"boot" => boot::main(rebuild_args("citadel-boot", args)),
|
||||
"install" => install::main(rebuild_args("citadel-install", args)),
|
||||
"image" => image::main(rebuild_args("citadel-image", args)),
|
||||
"mkimage" => mkimage::main(rebuild_args("citadel-mkimage", args)),
|
||||
_ => println!("Error: unknown command {}", command),
|
||||
}
|
||||
} else {
|
||||
println!("Must provide an argument");
|
||||
}
|
||||
}
|
||||
|
||||
fn rebuild_args(command: &str, args: Vec<String>) -> Vec<String> {
|
||||
iter::once(command.to_string())
|
||||
.chain(args.into_iter().skip(2))
|
||||
.collect()
|
||||
}
|
@ -6,7 +6,7 @@ use std::io::{self,Write};
|
||||
use failure::ResultExt;
|
||||
use libcitadel::{Result,ImageHeader,verity,util,devkeys};
|
||||
|
||||
use crate::BuildConfig;
|
||||
use super::config::BuildConfig;
|
||||
use std::path::Path;
|
||||
|
||||
pub struct UpdateBuilder {
|
31
citadel-tool/src/mkimage/mod.rs
Normal file
31
citadel-tool/src/mkimage/mod.rs
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
use std::process::exit;
|
||||
|
||||
use libcitadel::Result;
|
||||
|
||||
mod config;
|
||||
mod build;
|
||||
|
||||
pub fn main(args: Vec<String>) {
|
||||
|
||||
let config_path = match args.iter().skip(1).next() {
|
||||
Some(arg) => arg,
|
||||
None => {
|
||||
println!("Expected config file argument");
|
||||
exit(1);
|
||||
},
|
||||
};
|
||||
|
||||
if let Err(err) = build_image(config_path) {
|
||||
println!("Error: {}", err);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
fn build_image(config_path: &str) -> Result<()> {
|
||||
let conf = config::BuildConfig::load(config_path)?;
|
||||
let mut builder = build::UpdateBuilder::new(conf);
|
||||
builder.build()
|
||||
}
|
@ -6,7 +6,7 @@ use std::io::Write;
|
||||
use crate::{ImageHeader,MetaInfo,Mount,Result,util,verity};
|
||||
|
||||
const BASE_PATH: &'static str = "/storage/realms/realmfs-images";
|
||||
const RUN_DIRECTORY: &str = "/run/images";
|
||||
const RUN_DIRECTORY: &str = "/run/citadel/images";
|
||||
const MAX_REALMFS_NAME_LEN: usize = 40;
|
||||
|
||||
|
||||
|
@ -8,7 +8,7 @@ use crate::{CommandLine,OsRelease,ImageHeader,MetaInfo,Result,Partition,Mount,ve
|
||||
use failure::ResultExt;
|
||||
|
||||
const STORAGE_BASEDIR: &str = "/sysroot/storage/resources";
|
||||
const RUN_DIRECTORY: &str = "/run/images";
|
||||
const RUN_DIRECTORY: &str = "/run/citadel/images";
|
||||
|
||||
/// Locates and mounts a resource image file.
|
||||
///
|
||||
@ -24,7 +24,7 @@ const RUN_DIRECTORY: &str = "/run/images";
|
||||
/// citadel.noverity: Mount image without dm-verity. Also do not verify header signature.
|
||||
/// citadel.nosignatures: Do not verify header signature.
|
||||
///
|
||||
/// A requested image file will be searched for first in /run/images and if not found there the
|
||||
/// A requested image file will be searched for first in /run/citadel/images and if not found there the
|
||||
/// usual location of /storage/resources is searched.
|
||||
///
|
||||
pub struct ResourceImage {
|
||||
@ -35,7 +35,7 @@ pub struct ResourceImage {
|
||||
|
||||
impl ResourceImage {
|
||||
/// Locate and return a resource image of type `image_type`.
|
||||
/// First the /run/images directory is searched, and if not found there,
|
||||
/// First the /run/citadel/images directory is searched, and if not found there,
|
||||
/// the image will be searched for in /storage/resources/$channel
|
||||
pub fn find(image_type: &str) -> Result<ResourceImage> {
|
||||
let channel = ResourceImage::rootfs_channel();
|
||||
@ -59,7 +59,12 @@ impl ResourceImage {
|
||||
Err(format_err!("Failed to find resource image of type: {}", image_type))
|
||||
}
|
||||
|
||||
/// Locate a rootfs image in /run/images and return it
|
||||
pub fn mount_image_type(image_type: &str) -> Result<()> {
|
||||
let mut image = ResourceImage::find(image_type)?;
|
||||
image.mount()
|
||||
}
|
||||
|
||||
/// Locate a rootfs image in /run/citadel/images and return it
|
||||
pub fn find_rootfs() -> Result<ResourceImage> {
|
||||
match search_directory(RUN_DIRECTORY, "rootfs", None)? {
|
||||
Some(image) => Ok(image),
|
||||
|
@ -109,7 +109,7 @@ fn setup_device(srcdev: &str, devname: &str, nblocks: usize, roothash: &str) ->
|
||||
}
|
||||
|
||||
fn create_image_loop_device(file: &Path) -> Result<String> {
|
||||
let args = format!("--offset 4096 -f --show {}", file.display());
|
||||
let args = format!("--offset 4096 --read-only -f --show {}", file.display());
|
||||
let output = util::exec_cmdline_with_output(LOSETUP, args)?;
|
||||
Ok(output)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user