use std::path::{Path, PathBuf};
use anyhow::Result;
use nix::mount::MsFlags;
use crate::block::probe_value;
use crate::config::Config;
use crate::pipeline::{path_is_mount, unmount};
const MANIFEST_FILENAME: &str = "image.manifest";
pub fn running_in_container() -> bool {
std::env::var("container").as_deref() == Ok("podman")
}
fn read_manifest(source_image: &Path) -> Option<serde_json::Value> {
let manifest = source_image.parent()?.join(MANIFEST_FILENAME);
let data = std::fs::read_to_string(&manifest).ok()?;
serde_json::from_str(&data).ok()
}
fn manifest_field(source_image: Option<&Path>, key: &str) -> Option<String> {
let json = read_manifest(source_image?)?;
json.get(key).and_then(|v| v.as_str()).map(str::to_string)
}
pub fn load_target_imgref(source_image: Option<&Path>, config: &Config) -> String {
manifest_field(source_image, "target_imgref")
.unwrap_or_else(|| config.image.target_img_ref.clone())
}
pub fn load_image_version(source_image: Option<&Path>) -> String {
manifest_field(source_image, "version").unwrap_or_default()
}
pub fn image_manifest_metadata(source_image: &Path) -> serde_json::Value {
read_manifest(source_image).unwrap_or(serde_json::Value::Null)
}
pub fn image_source_ref(source_image: &Path) -> String {
if source_image.is_dir() {
return format!("dir:{}", source_image.display());
}
let ref_name = manifest_field(Some(source_image), "imgref").unwrap_or_default();
if ref_name.is_empty() {
return format!("oci-archive:{}", source_image.display());
}
let name = ref_name.strip_prefix("oci:").unwrap_or(&ref_name);
format!("oci-archive:{}:{}", source_image.display(), name)
}
pub fn default_source_image(config: &Config) -> Option<PathBuf> {
let mount = PathBuf::from(&config.image.source_mount);
let default_img = mount.join("image.tar");
if default_img.is_file() {
return Some(default_img);
}
if path_is_mount(&mount) {
let _ = unmount_default_source(config);
}
if running_in_container() {
return None;
}
let cache = blkid::cache::Cache::new().ok()?;
cache.probe_all().ok()?;
let dev = cache
.find_dev_with_tag(blkid::tag::Tag::new(
blkid::tag::SuperblockTag::Label,
&config.image.source_label,
))
.ok()??;
let device = dev.name().to_path_buf();
let device = device.to_str()?;
let fstype = probe_value(device, false, "TYPE").ok()?;
if fstype.is_empty() {
return None;
}
std::fs::create_dir_all(&mount).ok()?;
nix::mount::mount(
Some(device),
mount.as_path(),
Some(fstype.as_str()),
MsFlags::MS_RDONLY,
None::<&str>,
)
.ok()?;
if default_img.is_file() {
Some(default_img)
} else {
let _ = unmount_default_source(config);
None
}
}
fn unmount_default_source(config: &Config) -> Result<()> {
unmount(&PathBuf::from(&config.image.source_mount).to_string_lossy())
}