diff --git a/src/chroot.rs b/src/chroot.rs index 654646a..a43fe2f 100644 --- a/src/chroot.rs +++ b/src/chroot.rs @@ -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); diff --git a/src/main.rs b/src/main.rs index 5c70e50..c13db7c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ mod chroot; +mod utils; mod cli; mod config; mod distro; diff --git a/src/qemu_vm.rs b/src/qemu_vm.rs index 2fa910f..80f4a8a 100644 --- a/src/qemu_vm.rs +++ b/src/qemu_vm.rs @@ -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 2>&1 -c {}'\"", - hostname, hostname, cmd_str + "console=ttyS0 quiet rdinit=/bin/sh -- -c \"echo {} >/etc/hostname; hostname {}; setsid sh -c 'exec {} /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 2>&1'\"", - hostname, hostname + "console=ttyS0 quiet rdinit=/bin/sh -- -c \"echo {} >/etc/hostname; hostname {}; setsid sh -c 'exec {} /dev/ttyS0 2>&1'\"", + hostname, hostname, shell ) }; diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..44a283e --- /dev/null +++ b/src/utils.rs @@ -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 + } +}