Compare commits
3
Commits
cb87541151
...
5b80885207
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b80885207 | ||
|
|
d517ab6a1a | ||
|
|
e3bd77379f |
+1
-4
@@ -1,4 +1 @@
|
||||
/target/
|
||||
/target/debug/
|
||||
/target/release/
|
||||
Cargo.lock
|
||||
target
|
||||
|
||||
Generated
+368
@@ -0,0 +1,368 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
|
||||
|
||||
[[package]]
|
||||
name = "cpio"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "938e716cb1ade5d6c8f959c13a7248b889c07491fc7e41167c3afe20f8f0de1e"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8498c871161e1742aaa9d52551b2d6ebdd4c3d45a3be423e3728f33b955be550"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.189"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
|
||||
|
||||
[[package]]
|
||||
name = "slim"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"cpio",
|
||||
"flate2",
|
||||
"tempfile",
|
||||
"walkdir",
|
||||
"xdg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xdg"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fb433233f2df9344722454bc7e96465c9d03bff9d77c248f9e7523fe79585b5"
|
||||
+119
-35
@@ -1,11 +1,11 @@
|
||||
use anyhow::{Context, Result};
|
||||
use anyhow::{Context, Result, bail};
|
||||
use clap::{Parser, Subcommand};
|
||||
use flate2::write::GzEncoder;
|
||||
use std::fs::{self, File};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(name = "slim")]
|
||||
#[command(about = "Build bootable initrd VMs from container images")]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
@@ -42,10 +42,53 @@ fn main() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn registry_dir(image: &str) -> PathBuf {
|
||||
/// Validate a user-supplied image name before it is used in a registry path.
|
||||
///
|
||||
/// The name becomes a directory under `$XDG_DATA_HOME/slim-rs/registry/`, so
|
||||
/// path separators and `.`/`..` would allow escaping that directory.
|
||||
/// Allow-list: ASCII alphanumerics plus `.`, `_`, `:`, `-` (covers image
|
||||
/// refs like `alpine:3.15`).
|
||||
fn validate_image_name(name: &str) -> Result<()> {
|
||||
let valid = !name.is_empty()
|
||||
&& name != "."
|
||||
&& name != ".."
|
||||
&& name
|
||||
.chars()
|
||||
.all(|c| c.is_ascii_alphanumeric() || matches!(c, '.' | '_' | ':' | '-'));
|
||||
if !valid {
|
||||
bail!(
|
||||
"invalid image name '{name}': must be non-empty and contain only \
|
||||
alphanumerics, '.', '_', ':' and '-' (no path separators or '..')"
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn registry_dir(image: &str) -> Result<PathBuf> {
|
||||
validate_image_name(image)?;
|
||||
let base = xdg::BaseDirectories::with_prefix("slim-rs");
|
||||
let initrd_path = base.place_data_file(format!("registry/{}/initrd", image));
|
||||
initrd_path.unwrap().parent().unwrap().to_path_buf()
|
||||
let initrd_path = base
|
||||
.place_data_file(format!("registry/{image}/initrd"))
|
||||
.context("Failed to write to XDG_DATA_HOME")?;
|
||||
let reg_dir = initrd_path
|
||||
.parent()
|
||||
.expect("data file has a parent")
|
||||
.to_owned();
|
||||
|
||||
// Defense in depth: the constructed path must stay inside the registry.
|
||||
let registry_root = base
|
||||
.place_data_file("registry/.root-check")
|
||||
.context("Failed to write to XDG_DATA_HOME")?
|
||||
.parent()
|
||||
.expect("data file has a parent")
|
||||
.to_owned();
|
||||
if !reg_dir.starts_with(®istry_root) {
|
||||
bail!(
|
||||
"invalid image name '{image}': registry path escapes {}",
|
||||
registry_root.display()
|
||||
);
|
||||
}
|
||||
Ok(reg_dir)
|
||||
}
|
||||
|
||||
fn build(image: &str) -> Result<()> {
|
||||
@@ -75,7 +118,7 @@ fn mount_image(image: &str) -> Result<PathBuf> {
|
||||
.context("Failed to run podman image mount")?;
|
||||
let mount_path = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||
if !output.status.success() || mount_path.is_empty() {
|
||||
anyhow::bail!(
|
||||
bail!(
|
||||
"podman image mount failed: {}",
|
||||
String::from_utf8_lossy(&output.stderr).trim()
|
||||
);
|
||||
@@ -95,12 +138,10 @@ fn build_artifacts(image: &str, mount_path: &Path) -> Result<()> {
|
||||
.status()
|
||||
.context("Failed to check for /vmlinuz inside the image mount")?;
|
||||
if !has_kernel.success() {
|
||||
anyhow::bail!(
|
||||
"Image missing required /vmlinuz. Place kernel at /vmlinuz in Containerfile."
|
||||
);
|
||||
bail!("Image missing required /vmlinuz. Place kernel at /vmlinuz in Containerfile.");
|
||||
}
|
||||
|
||||
let reg_dir = registry_dir(image);
|
||||
let reg_dir = registry_dir(image)?;
|
||||
fs::create_dir_all(®_dir)?;
|
||||
println!("Registry: {}", reg_dir.display());
|
||||
|
||||
@@ -116,7 +157,7 @@ fn build_artifacts(image: &str, mount_path: &Path) -> Result<()> {
|
||||
.status()
|
||||
.context("Failed to copy vmlinuz out of the image mount")?;
|
||||
if !cp_status.success() {
|
||||
anyhow::bail!("Failed to copy vmlinuz to registry");
|
||||
bail!("Failed to copy vmlinuz to registry");
|
||||
}
|
||||
println!("Copied vmlinuz -> {}", vmlinuz_dst.display());
|
||||
|
||||
@@ -132,7 +173,7 @@ fn build_artifacts(image: &str, mount_path: &Path) -> Result<()> {
|
||||
.context("Failed to spawn the cpio pipeline")?;
|
||||
|
||||
let initrd_file = File::create(&initrd_path).context("Failed to create initrd file")?;
|
||||
let mut encoder = flate2::write::GzEncoder::new(initrd_file, flate2::Compression::default());
|
||||
let mut encoder = GzEncoder::new(initrd_file, flate2::Compression::default());
|
||||
let cpio_stdout = cpio.stdout.take().context("cpio stdout was not piped")?;
|
||||
let copied = std::io::copy(&mut std::io::BufReader::new(cpio_stdout), &mut encoder);
|
||||
let stream_result = copied
|
||||
@@ -148,7 +189,7 @@ fn build_artifacts(image: &str, mount_path: &Path) -> Result<()> {
|
||||
}
|
||||
if !cpio_status.success() {
|
||||
let _ = fs::remove_file(&initrd_path);
|
||||
anyhow::bail!("find/cpio pipeline failed with status {cpio_status}");
|
||||
bail!("find/cpio pipeline failed with status {cpio_status}");
|
||||
}
|
||||
println!("Created initrd -> {}", initrd_path.display());
|
||||
|
||||
@@ -156,11 +197,11 @@ fn build_artifacts(image: &str, mount_path: &Path) -> Result<()> {
|
||||
}
|
||||
|
||||
fn run(name: &str) -> Result<()> {
|
||||
let reg_dir = registry_dir(name);
|
||||
let reg_dir = registry_dir(name)?;
|
||||
let vmlinuz_path = reg_dir.join("vmlinuz");
|
||||
let initrd_path = reg_dir.join("initrd");
|
||||
if !vmlinuz_path.exists() || !initrd_path.exists() {
|
||||
anyhow::bail!(
|
||||
bail!(
|
||||
"Registry missing vmlinuz/initrd for '{}'. Run `slim build` first.",
|
||||
name
|
||||
);
|
||||
@@ -171,34 +212,77 @@ fn run(name: &str) -> Result<()> {
|
||||
vmlinuz_path.display(),
|
||||
initrd_path.display()
|
||||
);
|
||||
|
||||
let cmdline = [
|
||||
"console=ttyS0,115200",
|
||||
"root=/dev/ram0",
|
||||
"rw",
|
||||
"earlyprintk=serial",
|
||||
"nokaslr",
|
||||
"raid=noautodetect",
|
||||
]
|
||||
.join(" ");
|
||||
|
||||
// Launch with a 5-second timeout for quick smoke verification
|
||||
let status = Command::new("timeout")
|
||||
.args([
|
||||
"5",
|
||||
"qemu-system-x86_64",
|
||||
"-m",
|
||||
"256",
|
||||
"-nographic",
|
||||
"-kernel",
|
||||
vmlinuz_path.to_str().unwrap(),
|
||||
"-initrd",
|
||||
initrd_path.to_str().unwrap(),
|
||||
"-append",
|
||||
"console=ttyS0",
|
||||
])
|
||||
let status = Command::new("qemu-system-x86_64")
|
||||
.args(["-m", "1024M"])
|
||||
.arg("-kernel")
|
||||
.arg(vmlinuz_path.as_os_str())
|
||||
.arg("-initrd")
|
||||
.arg(initrd_path.as_os_str())
|
||||
.args(["-append", &cmdline])
|
||||
.args(["-nographic"])
|
||||
.status()
|
||||
.context("Failed to launch qemu-system-x86_64")?;
|
||||
|
||||
// `timeout` exits 124 when it kills QEMU after the 5s smoke-test
|
||||
// window; any other non-zero status is a real failure.
|
||||
match status.code() {
|
||||
Some(0) => println!("QEMU exited cleanly."),
|
||||
Some(124) => println!("QEMU timed out after 5s (expected during smoke boot)."),
|
||||
Some(126) | Some(127) => {
|
||||
anyhow::bail!("Failed to start qemu-system-x86_64 (is it installed and in PATH?)")
|
||||
bail!("Failed to start qemu-system-x86_64 (is it installed and in PATH?)")
|
||||
}
|
||||
Some(code) => anyhow::bail!("QEMU exited with code {code}"),
|
||||
None => anyhow::bail!("QEMU terminated by a signal"),
|
||||
Some(code) => bail!("QEMU exited with code {code}"),
|
||||
None => bail!("QEMU terminated by a signal"),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::validate_image_name;
|
||||
|
||||
#[test]
|
||||
fn accepts_valid_image_names() {
|
||||
for name in [
|
||||
"alpine:3.15",
|
||||
"slim",
|
||||
"mock-vm",
|
||||
"my_vm",
|
||||
"a.b.c",
|
||||
"vm-1.2.3",
|
||||
] {
|
||||
validate_image_name(name).unwrap_or_else(|e| panic!("{name} rejected: {e}"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_traversal_and_separators() {
|
||||
for name in [
|
||||
"",
|
||||
".",
|
||||
"..",
|
||||
"../evil",
|
||||
"../../tmp/evil",
|
||||
"a/b",
|
||||
"/abs",
|
||||
"a\\b",
|
||||
"foo bar",
|
||||
"vm;rm",
|
||||
"vm\n",
|
||||
] {
|
||||
assert!(
|
||||
validate_image_name(name).is_err(),
|
||||
"{name:?} should be rejected"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user