citadel-tools/citadel-tool/src/boot/live.rs

167 lines
4.9 KiB
Rust
Raw Normal View History

2018-12-31 23:27:17 +00:00
use std::path::Path;
use std::ffi::OsStr;
use std::fs;
2019-04-02 19:26:09 +00:00
use std::thread::{self,JoinHandle};
use std::time::{self,Instant};
2018-12-31 23:27:17 +00:00
use libcitadel::{Result, UtsName};
use libcitadel::ResourceImage;
use crate::boot::disks;
use crate::boot::rootfs::setup_rootfs_resource;
use crate::install::installer::Installer;
2018-12-31 23:27:17 +00:00
const IMAGE_DIRECTORY: &str = "/run/citadel/images";
2018-12-31 23:27:17 +00:00
pub fn live_rootfs() -> Result<()> {
copy_artifacts()?;
let rootfs = find_rootfs_image()?;
setup_rootfs_resource(&rootfs)
2018-12-31 23:27:17 +00:00
}
pub fn live_setup() -> Result<()> {
decompress_images()?;
2019-04-02 19:26:09 +00:00
info!("Starting live setup");
let live = Installer::new_livesetup();
live.run()
2018-12-31 23:27:17 +00:00
}
fn copy_artifacts() -> Result<()> {
for _ in 0..3 {
if try_copy_artifacts()? {
//decompress_images()?;
2018-12-31 23:27:17 +00:00
return Ok(())
}
// Try again after waiting for more devices to be discovered
info!("Failed to find partition with images, trying again in 2 seconds");
2018-12-31 23:27:17 +00:00
thread::sleep(time::Duration::from_secs(2));
}
Err(format_err!("Could not find partition containing resource images"))
2018-12-31 23:27:17 +00:00
}
fn try_copy_artifacts() -> Result<bool> {
let rootfs_image = Path::new("/boot/images/citadel-rootfs.img");
// Already mounted?
if rootfs_image.exists() {
deploy_artifacts()?;
return Ok(true);
}
for part in disks::DiskPartition::boot_partitions(false)? {
2018-12-31 23:27:17 +00:00
part.mount("/boot")?;
if rootfs_image.exists() {
deploy_artifacts()?;
part.umount()?;
return Ok(true);
}
part.umount()?;
}
Ok(false)
}
fn kernel_version() -> String {
let utsname = UtsName::uname();
let v = utsname.release().split('-').collect::<Vec<_>>();
v[0].to_string()
}
2018-12-31 23:27:17 +00:00
fn deploy_artifacts() -> Result<()> {
let run_images = Path::new(IMAGE_DIRECTORY);
2018-12-31 23:27:17 +00:00
if !run_images.exists() {
fs::create_dir_all(run_images)?;
2019-04-02 19:26:09 +00:00
cmd!("/bin/mount", "-t tmpfs -o size=4g images /run/citadel/images")?;
2018-12-31 23:27:17 +00:00
}
for entry in fs::read_dir("/boot/images")? {
let entry = entry?;
println!("Copying {:?} from /boot/images to /run/citadel/images", entry.file_name());
2018-12-31 23:27:17 +00:00
fs::copy(entry.path(), run_images.join(entry.file_name()))?;
}
let kv = kernel_version();
println!("Copying bzImage-{} to /run/citadel/images", kv);
let from = format!("/boot/bzImage-{}", kv);
let to = format!("/run/citadel/images/bzImage-{}", kv);
fs::copy(from, to)?;
2018-12-31 23:27:17 +00:00
println!("Copying bootx64.efi to /run/citadel/images");
fs::copy("/boot/EFI/BOOT/bootx64.efi", "/run/citadel/images/bootx64.efi")?;
2018-12-31 23:27:17 +00:00
deploy_syslinux_artifacts()?;
Ok(())
}
fn deploy_syslinux_artifacts() -> Result<()> {
let boot_syslinux = Path::new("/boot/syslinux");
if !boot_syslinux.exists() {
println!("Not copying syslinux components because /boot/syslinux does not exist");
return Ok(());
}
println!("Copying contents of /boot/syslinux to /run/citadel/images/syslinux");
2018-12-31 23:27:17 +00:00
let run_images_syslinux = Path::new("/run/citadel/images/syslinux");
2018-12-31 23:27:17 +00:00
fs::create_dir_all(run_images_syslinux)?;
for entry in fs::read_dir(boot_syslinux)? {
let entry = entry?;
if let Some(ext) = entry.path().extension() {
if ext == "c32" || ext == "bin" {
fs::copy(entry.path(), run_images_syslinux.join(entry.file_name()))?;
}
}
}
Ok(())
}
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<()> {
2019-04-02 19:26:09 +00:00
info!("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()?;
}
2019-04-02 19:26:09 +00:00
info!("Finished decompressing images");
Ok(())
}
fn decompress_one_image(image: ResourceImage) -> JoinHandle<Result<()>> {
2019-04-02 19:26:09 +00:00
thread::spawn(move || {
let start = Instant::now();
info!("Decompressing {}", image.path().display());
image.decompress()?;
cmd!("/usr/bin/du", "-h {}", image.path().display())?;
info!("Decompress {:?} finished in {} seconds",
image.path().file_name().unwrap(),
start.elapsed().as_secs());
Ok(())
})
}