feat: detect shell for --kernel

- Move detect_shell() to new src/utils.rs for reuse
- Use detected shell in QEMU VM mode (bash when available)
- Update chroot.rs and qemu_vm.rs to use shared function
This commit is contained in:
2026-06-17 11:13:05 +02:00
parent d52310c0f4
commit 7a37f99030
4 changed files with 30 additions and 16 deletions
+3 -12
View File
@@ -18,22 +18,13 @@ pub fn run_chroot(
eprintln!("Warning: Failed to set hostname: {}", e);
}
// Detect shell before chroot (we're still outside)
let shell = crate::utils::detect_shell(rootfs);
// Change to root directory in chroot
chroot(rootfs).context("Failed to chroot")?;
// Now we're inside the chroot - set up environment based on chroot filesystem
// Determine shell path (check inside chroot, not host)
let shell = if Path::new("/bin/bash").exists() {
"/bin/bash"
} else if Path::new("/bin/sh").exists() {
"/bin/sh"
} else if Path::new("/usr/bin/bash").exists() {
"/usr/bin/bash"
} else if Path::new("/usr/bin/sh").exists() {
"/usr/bin/sh"
} else {
"/bin/sh" // Will fail with clear error if not present
};
// Set up environment variables (after chroot, so paths are correct)
let env = setup_environment(shell, &host_term);
+1
View File
@@ -1,4 +1,5 @@
mod chroot;
mod utils;
mod cli;
mod config;
mod distro;
+7 -4
View File
@@ -54,6 +54,9 @@ pub fn launch_qemu(config: QemuConfig) -> Result<()> {
qemu_bin, get_arch_package_suffix(&config.arch), get_arch_package_suffix(&config.arch), get_arch_package_suffix(&config.arch)
))?;
// Detect the best available shell in the rootfs
let shell = crate::utils::detect_shell(&config.rootfs_path);
// Generate a unique hostname like "ecr-vm-a1b2c3"
let hostname_suffix = format!("{:x}", (std::process::id() as u64)
.wrapping_mul(std::time::SystemTime::now()
@@ -72,14 +75,14 @@ pub fn launch_qemu(config: QemuConfig) -> Result<()> {
let kernel_append = if let Some(ref cmd) = config.command {
let cmd_str = cmd.join(" ");
format!(
"console=ttyS0 quiet rdinit=/bin/sh -- -c \"echo {} >/etc/hostname; hostname {}; setsid sh -c 'exec sh </dev/ttyS0 >/dev/ttyS0 2>&1 -c {}'\"",
hostname, hostname, cmd_str
"console=ttyS0 quiet rdinit=/bin/sh -- -c \"echo {} >/etc/hostname; hostname {}; setsid sh -c 'exec {} </dev/ttyS0 >/dev/ttyS0 2>&1 -c {}'\"",
hostname, hostname, shell, cmd_str
)
} else {
// Default to interactive shell with proper job control
format!(
"console=ttyS0 quiet rdinit=/bin/sh -- -c \"echo {} >/etc/hostname; hostname {}; setsid sh -c 'exec sh </dev/ttyS0 >/dev/ttyS0 2>&1'\"",
hostname, hostname
"console=ttyS0 quiet rdinit=/bin/sh -- -c \"echo {} >/etc/hostname; hostname {}; setsid sh -c 'exec {} </dev/ttyS0 >/dev/ttyS0 2>&1'\"",
hostname, hostname, shell
)
};
+19
View File
@@ -0,0 +1,19 @@
use std::path::Path;
/// Detect the best available shell in a rootfs
/// Checks for bash first, falls back to sh
/// Returns the path relative to the rootfs (e.g., "/bin/bash")
pub fn detect_shell(rootfs: &Path) -> &'static str {
// Check for bash first (preferred)
if rootfs.join("bin/bash").exists() {
"/bin/bash"
} else if rootfs.join("bin/sh").exists() {
"/bin/sh"
} else if rootfs.join("usr/bin/bash").exists() {
"/usr/bin/bash"
} else if rootfs.join("usr/bin/sh").exists() {
"/usr/bin/sh"
} else {
"/bin/sh" // Will fail with clear error if not present
}
}