From 2dc32d1f20c1e0c25b7cb109f6e70fbef153dd9e Mon Sep 17 00:00:00 2001 From: Bruce Leidl Date: Wed, 30 Jan 2019 21:31:13 -0500 Subject: [PATCH] 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. --- Cargo.lock | 44 ++---- Cargo.toml | 6 +- citadel-install/Cargo.toml | 12 -- citadel-mount/Cargo.toml | 10 -- citadel-mount/src/main.rs | 94 ------------- {citadel-image => citadel-tool}/Cargo.toml | 6 +- .../src => citadel-tool/src/boot}/disks.rs | 4 +- .../main.rs => citadel-tool/src/boot/live.rs | 133 +++++++----------- citadel-tool/src/boot/mod.rs | 74 ++++++++++ .../src => citadel-tool/src/boot}/rootfs.rs | 23 +-- .../main.rs => citadel-tool/src/image/mod.rs | 45 ++---- .../src => citadel-tool/src/install}/cli.rs | 6 +- .../src/install/disk.rs | 54 +------ .../src/install}/installer.rs | 34 ++--- citadel-tool/src/install/mod.rs | 28 ++++ citadel-tool/src/main.rs | 58 ++++++++ .../src => citadel-tool/src/mkimage}/build.rs | 2 +- .../src/mkimage}/config.rs | 0 citadel-tool/src/mkimage/mod.rs | 31 ++++ libcitadel/src/realmfs.rs | 2 +- libcitadel/src/resource.rs | 13 +- libcitadel/src/verity.rs | 2 +- 22 files changed, 320 insertions(+), 361 deletions(-) delete mode 100644 citadel-install/Cargo.toml delete mode 100644 citadel-mount/Cargo.toml delete mode 100644 citadel-mount/src/main.rs rename {citadel-image => citadel-tool}/Cargo.toml (71%) rename {citadel-install/src => citadel-tool/src/boot}/disks.rs (98%) rename citadel-install/src/main.rs => citadel-tool/src/boot/live.rs (53%) create mode 100644 citadel-tool/src/boot/mod.rs rename {citadel-mount/src => citadel-tool/src/boot}/rootfs.rs (88%) rename citadel-image/src/main.rs => citadel-tool/src/image/mod.rs (90%) rename {citadel-install/src => citadel-tool/src/install}/cli.rs (97%) rename citadel-install/src/util.rs => citadel-tool/src/install/disk.rs (68%) rename {citadel-install/src => citadel-tool/src/install}/installer.rs (94%) create mode 100644 citadel-tool/src/install/mod.rs create mode 100644 citadel-tool/src/main.rs rename {citadel-image/src => citadel-tool/src/mkimage}/build.rs (99%) rename {citadel-image/src => citadel-tool/src/mkimage}/config.rs (100%) create mode 100644 citadel-tool/src/mkimage/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 83d30fa..761279b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 94f00e2..1857050 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 diff --git a/citadel-install/Cargo.toml b/citadel-install/Cargo.toml deleted file mode 100644 index 48fb04f..0000000 --- a/citadel-install/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "citadel-install" -version = "0.1.0" -authors = ["Bruce Leidl "] -homepage = "http://github.com/subgraph/citadel" -edition = "2018" - -[dependencies] -libcitadel = { path = "../libcitadel" } -failure = "0.1.3" -libc = "0.2" -rpassword = "2.1.0" diff --git a/citadel-mount/Cargo.toml b/citadel-mount/Cargo.toml deleted file mode 100644 index d4eb9ed..0000000 --- a/citadel-mount/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "citadel-mount" -version = "0.1.0" -authors = ["Bruce Leidl "] -homepage = "http://github.com/subgraph/citadel" - -[dependencies] -libcitadel = { path = "../libcitadel" } -failure = "0.1.3" -libc = "0.2" diff --git a/citadel-mount/src/main.rs b/citadel-mount/src/main.rs deleted file mode 100644 index 1822d29..0000000 --- a/citadel-mount/src/main.rs +++ /dev/null @@ -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(()) -} diff --git a/citadel-image/Cargo.toml b/citadel-tool/Cargo.toml similarity index 71% rename from citadel-image/Cargo.toml rename to citadel-tool/Cargo.toml index 8f0391b..06b4262 100644 --- a/citadel-image/Cargo.toml +++ b/citadel-tool/Cargo.toml @@ -1,14 +1,14 @@ [package] -name = "citadel-image" +name = "citadel-tool" version = "0.1.0" authors = ["Bruce Leidl "] -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" diff --git a/citadel-install/src/disks.rs b/citadel-tool/src/boot/disks.rs similarity index 98% rename from citadel-install/src/disks.rs rename to citadel-tool/src/boot/disks.rs index 8fe1008..7e2f86d 100644 --- a/citadel-install/src/disks.rs +++ b/citadel-tool/src/boot/disks.rs @@ -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 diff --git a/citadel-install/src/main.rs b/citadel-tool/src/boot/live.rs similarity index 53% rename from citadel-install/src/main.rs rename to citadel-tool/src/boot/live.rs index a1fa3a6..4372bc8 100644 --- a/citadel-install/src/main.rs +++ b/citadel-tool/src/boot/live.rs @@ -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 = result::Result; +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 { @@ -89,22 +61,22 @@ fn try_copy_artifacts() -> Result { } 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,14 +106,31 @@ 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 { + 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()) { - threads.push(decompress_one_image(image)); + 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)); + } } } } @@ -157,19 +146,3 @@ fn decompress_one_image(image: ResourceImage) -> JoinHandle> { 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(()) -} diff --git a/citadel-tool/src/boot/mod.rs b/citadel-tool/src/boot/mod.rs new file mode 100644 index 0000000..046816e --- /dev/null +++ b/citadel-tool/src/boot/mod.rs @@ -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) { + 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(()) +} diff --git a/citadel-mount/src/rootfs.rs b/citadel-tool/src/boot/rootfs.rs similarity index 88% rename from citadel-mount/src/rootfs.rs rename to citadel-tool/src/boot/rootfs.rs index 3d53318..95c8135 100644 --- a/citadel-mount/src/rootfs.rs +++ b/citadel-tool/src/boot/rootfs.rs @@ -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) } } diff --git a/citadel-image/src/main.rs b/citadel-tool/src/image/mod.rs similarity index 90% rename from citadel-image/src/main.rs rename to citadel-tool/src/image/mod.rs index a873c0d..ce2eef8 100644 --- a/citadel-image/src/main.rs +++ b/citadel-tool/src/image/mod.rs @@ -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) { -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") @@ -72,14 +60,13 @@ fn main() { .subcommand(SubCommand::with_name("verify-shasum") .about("Verify the sha256 sum of the image") .arg(Arg::with_name("path") - .required(true) - .help("Path to image file"))); + .required(true) + .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())?); @@ -238,7 +217,7 @@ fn install_image(arg_matches: &ArgMatches) -> Result<()> { let image_dir = Path::new("/storage/resources").join(metainfo.channel()); let image_dest = image_dir.join(filename); if image_dest.exists() { - rotate(&image_dest)?; + rotate(&image_dest)?; } fs::rename(source,image_dest)?; Ok(()) @@ -299,9 +278,9 @@ fn choose_install_partition(verbose: bool) -> Result { if verbose { for p in &partitions { info!("Partition: {} (Mounted: {}) (Empty: {})", - p.path().display(), - bool_to_yesno(p.is_mounted()), - bool_to_yesno(!p.is_initialized())); + p.path().display(), + bool_to_yesno(p.is_mounted()), + bool_to_yesno(!p.is_initialized())); } } diff --git a/citadel-install/src/cli.rs b/citadel-tool/src/install/cli.rs similarity index 97% rename from citadel-install/src/cli.rs rename to citadel-tool/src/install/cli.rs index 1191e3c..5ceb2f3 100644 --- a/citadel-install/src/cli.rs +++ b/citadel-tool/src/install/cli.rs @@ -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 { let disk = match choose_disk()? { diff --git a/citadel-install/src/util.rs b/citadel-tool/src/install/disk.rs similarity index 68% rename from citadel-install/src/util.rs rename to citadel-tool/src/install/disk.rs index a50f07a..c87174a 100644 --- a/citadel-install/src/util.rs +++ b/citadel-tool/src/install/disk.rs @@ -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(()) } +*/ diff --git a/citadel-install/src/installer.rs b/citadel-tool/src/install/installer.rs similarity index 94% rename from citadel-install/src/installer.rs rename to citadel-tool/src/install/installer.rs index 7d771b5..33ba089 100644 --- a/citadel-install/src/installer.rs +++ b/citadel-tool/src/install/installer.rs @@ -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)?; diff --git a/citadel-tool/src/install/mod.rs b/citadel-tool/src/install/mod.rs new file mode 100644 index 0000000..8b64f39 --- /dev/null +++ b/citadel-tool/src/install/mod.rs @@ -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) { + 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..."); + } +} + diff --git a/citadel-tool/src/main.rs b/citadel-tool/src/main.rs new file mode 100644 index 0000000..79675eb --- /dev/null +++ b/citadel-tool/src/main.rs @@ -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::>(); + + 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) { + 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) -> Vec { + iter::once(command.to_string()) + .chain(args.into_iter().skip(2)) + .collect() +} diff --git a/citadel-image/src/build.rs b/citadel-tool/src/mkimage/build.rs similarity index 99% rename from citadel-image/src/build.rs rename to citadel-tool/src/mkimage/build.rs index b7a8272..908b923 100644 --- a/citadel-image/src/build.rs +++ b/citadel-tool/src/mkimage/build.rs @@ -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 { diff --git a/citadel-image/src/config.rs b/citadel-tool/src/mkimage/config.rs similarity index 100% rename from citadel-image/src/config.rs rename to citadel-tool/src/mkimage/config.rs diff --git a/citadel-tool/src/mkimage/mod.rs b/citadel-tool/src/mkimage/mod.rs new file mode 100644 index 0000000..5c31d0c --- /dev/null +++ b/citadel-tool/src/mkimage/mod.rs @@ -0,0 +1,31 @@ + +use std::process::exit; + +use libcitadel::Result; + +mod config; +mod build; + +pub fn main(args: Vec) { + + 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() +} \ No newline at end of file diff --git a/libcitadel/src/realmfs.rs b/libcitadel/src/realmfs.rs index aad6f79..b45d52d 100644 --- a/libcitadel/src/realmfs.rs +++ b/libcitadel/src/realmfs.rs @@ -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; diff --git a/libcitadel/src/resource.rs b/libcitadel/src/resource.rs index b44a32e..ca6961c 100644 --- a/libcitadel/src/resource.rs +++ b/libcitadel/src/resource.rs @@ -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 { 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 { match search_directory(RUN_DIRECTORY, "rootfs", None)? { Some(image) => Ok(image), diff --git a/libcitadel/src/verity.rs b/libcitadel/src/verity.rs index b789601..4300b9a 100644 --- a/libcitadel/src/verity.rs +++ b/libcitadel/src/verity.rs @@ -109,7 +109,7 @@ fn setup_device(srcdev: &str, devname: &str, nblocks: usize, roothash: &str) -> } fn create_image_loop_device(file: &Path) -> Result { - 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) }