use std::path::PathBuf;
use std::process::Command;
pub fn find_ms_sys() -> Result<PathBuf, String> {
if let Ok(p) = std::env::var("MKMSBR_MS_SYS") {
let p = PathBuf::from(p);
if p.exists() {
return Ok(p);
}
return Err(format!("MKMSBR_MS_SYS={} does not exist", p.display()));
}
for candidate in &[
"/tmp/ms-sys/bin/ms-sys",
"/usr/local/bin/ms-sys",
"/opt/homebrew/bin/ms-sys",
] {
let p = PathBuf::from(candidate);
if p.exists() {
return Ok(p);
}
}
let out = Command::new("/usr/bin/env")
.args(["which", "ms-sys"])
.output()
.map_err(|e| e.to_string())?;
if out.status.success() {
let path = String::from_utf8_lossy(&out.stdout).trim().to_string();
if !path.is_empty() {
return Ok(PathBuf::from(path));
}
}
Err(
"ms-sys not found. Install with `git clone https://gitlab.com/cmaiolino/ms-sys.git \
/tmp/ms-sys && cd /tmp/ms-sys && make`, or set MKMSBR_MS_SYS."
.to_string(),
)
}
pub fn run_ms_sys(args: &[&str], image: &std::path::Path) -> Result<(), String> {
let bin = find_ms_sys()?;
let mut cmd = Command::new(&bin);
cmd.args(args).arg(image);
let out = cmd.output().map_err(|e| format!("spawning ms-sys: {e}"))?;
if !out.status.success() {
return Err(format!(
"ms-sys {args:?} failed: {}\nstdout: {}",
String::from_utf8_lossy(&out.stderr),
String::from_utf8_lossy(&out.stdout)
));
}
Ok(())
}
pub fn ms_sys_mbr_win7_bootcode() -> Result<[u8; 440], String> {
mbr_boot_code(&["--mbr7"])
}
pub fn ms_sys_mbr_xp_bootcode() -> Result<[u8; 440], String> {
mbr_boot_code(&["--mbr"])
}
fn mbr_boot_code(args: &[&str]) -> Result<[u8; 440], String> {
use std::io::Read;
let tmp = std::env::temp_dir().join(format!(
"mkmsbr-oracle-{}-{}",
args[0].trim_start_matches('-'),
std::process::id()
));
std::fs::write(&tmp, vec![0u8; 1024 * 1024]).map_err(|e| format!("seed image: {e}"))?;
let mut full_args: Vec<&str> = args.to_vec();
full_args.push("-f");
run_ms_sys(&full_args, &tmp)?;
let mut f = std::fs::File::open(&tmp).map_err(|e| format!("open: {e}"))?;
let mut buf = [0u8; 512];
f.read_exact(&mut buf).map_err(|e| format!("read: {e}"))?;
let _ = std::fs::remove_file(&tmp);
let mut out = [0u8; 440];
out.copy_from_slice(&buf[0..440]);
Ok(out)
}
pub fn ms_sys_fat32_bootmgr_pbr() -> Result<[u8; 512], String> {
fat32_pbr_sector0(&["--fat32pe"])
}
pub fn ms_sys_fat32_ntldr_pbr() -> Result<[u8; 512], String> {
fat32_pbr_sector0(&["--fat32nt"])
}
pub fn ms_sys_fat32_bootmgr_pbr_multi() -> Result<[u8; 8192], String> {
fat32_pbr_sectors_0_15(&["--fat32pe"])
}
fn fat32_pbr_sector0(args: &[&str]) -> Result<[u8; 512], String> {
use std::io::Read;
let tmp = std::env::temp_dir().join(format!(
"mkmsbr-pbr-oracle-{}-{}",
args[0].trim_start_matches('-'),
std::process::id()
));
std::fs::write(&tmp, vec![0u8; 64 * 1024 * 1024])
.map_err(|e| format!("seed image: {e}"))?;
let fmt = std::process::Command::new("mformat")
.args(["-F", "-i"])
.arg(&tmp)
.args(["-v", "MKMSBR", "::"])
.output()
.map_err(|e| format!("mformat: {e}"))?;
if !fmt.status.success() {
return Err(format!(
"mformat failed: {}",
String::from_utf8_lossy(&fmt.stderr)
));
}
let mut full_args: Vec<&str> = args.to_vec();
full_args.push("-f");
run_ms_sys(&full_args, &tmp)?;
let mut f = std::fs::File::open(&tmp).map_err(|e| format!("open: {e}"))?;
let mut buf = [0u8; 512];
f.read_exact(&mut buf).map_err(|e| format!("read: {e}"))?;
let _ = std::fs::remove_file(&tmp);
Ok(buf)
}
pub fn ms_sys_ntfs_pbr_sector0() -> Result<[u8; 512], String> {
ntfs_pbr_sector0(&["--ntfs"])
}
pub fn ms_sys_ntfs_pbr_sectors_0_15() -> Result<[u8; 8192], String> {
ntfs_pbr_sectors_0_15(&["--ntfs"])
}
fn ntfs_pbr_sector0(args: &[&str]) -> Result<[u8; 512], String> {
use std::io::Read;
let tmp = std::env::temp_dir().join(format!(
"mkmsbr-ntfs-pbr-oracle-{}-{}",
args[0].trim_start_matches('-'),
std::process::id()
));
super::ntfs_image::mkfs_ntfs(&tmp, 64 * 1024 * 1024)?;
let mut full_args: Vec<&str> = args.to_vec();
full_args.push("-f");
run_ms_sys(&full_args, &tmp)?;
let mut f = std::fs::File::open(&tmp).map_err(|e| format!("open: {e}"))?;
let mut buf = [0u8; 512];
f.read_exact(&mut buf).map_err(|e| format!("read: {e}"))?;
let _ = std::fs::remove_file(&tmp);
Ok(buf)
}
fn ntfs_pbr_sectors_0_15(args: &[&str]) -> Result<[u8; 8192], String> {
use std::io::Read;
let tmp = std::env::temp_dir().join(format!(
"mkmsbr-ntfs-pbr-oracle-multi-{}-{}",
args[0].trim_start_matches('-'),
std::process::id()
));
super::ntfs_image::mkfs_ntfs(&tmp, 64 * 1024 * 1024)?;
let mut full_args: Vec<&str> = args.to_vec();
full_args.push("-f");
run_ms_sys(&full_args, &tmp)?;
let mut f = std::fs::File::open(&tmp).map_err(|e| format!("open: {e}"))?;
let mut buf = [0u8; 8192];
f.read_exact(&mut buf).map_err(|e| format!("read: {e}"))?;
let _ = std::fs::remove_file(&tmp);
Ok(buf)
}
fn fat32_pbr_sectors_0_15(args: &[&str]) -> Result<[u8; 8192], String> {
use std::io::Read;
let tmp = std::env::temp_dir().join(format!(
"mkmsbr-pbr-oracle-multi-{}-{}",
args[0].trim_start_matches('-'),
std::process::id()
));
std::fs::write(&tmp, vec![0u8; 64 * 1024 * 1024])
.map_err(|e| format!("seed image: {e}"))?;
let fmt = std::process::Command::new("mformat")
.args(["-F", "-i"])
.arg(&tmp)
.args(["-v", "MKMSBR", "::"])
.output()
.map_err(|e| format!("mformat: {e}"))?;
if !fmt.status.success() {
return Err(format!(
"mformat failed: {}",
String::from_utf8_lossy(&fmt.stderr)
));
}
let mut full_args: Vec<&str> = args.to_vec();
full_args.push("-f");
run_ms_sys(&full_args, &tmp)?;
let mut f = std::fs::File::open(&tmp).map_err(|e| format!("open: {e}"))?;
let mut buf = [0u8; 8192];
f.read_exact(&mut buf).map_err(|e| format!("read: {e}"))?;
let _ = std::fs::remove_file(&tmp);
Ok(buf)
}