#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
use std::path::{Path, PathBuf};
use std::process;
use std::time::{SystemTime, UNIX_EPOCH};
use supermachine::{Image, VmConfig};
fn required_env(name: &str) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
std::env::var(name).map_err(|_| format!("missing required env var {name}").into())
}
fn host_ns() -> u128 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("host clock before unix epoch")
.as_nanos()
}
fn run_child(
label: &'static str,
node: Image,
) -> Result<(String, String, String), Box<dyn std::error::Error + Send + Sync>> {
let vm = node.start(&VmConfig::new())?;
let host_before = host_ns();
let script = format!(
r#"set -eu
label={label}
host_before_ns={host_before}
guest_date_ns_0=$(date +%s%N)
guest_uptime_0=$(cut -d' ' -f1 /proc/uptime)
guest_uuid=$(cat /proc/sys/kernel/random/uuid)
guest_urandom16=$(od -An -N16 -tx1 /dev/urandom | tr -d ' \n')
echo "CLOCK label=${{label}} phase=immediate host_before_ns=${{host_before_ns}} guest_date_ns=${{guest_date_ns_0}} guest_uptime_s=${{guest_uptime_0}}"
echo "IDENTITY label=${{label}} uuid=${{guest_uuid}} urandom16=${{guest_urandom16}}"
sleep 5
guest_date_ns_5=$(date +%s%N)
guest_uptime_5=$(cut -d' ' -f1 /proc/uptime)
echo "CLOCK label=${{label}} phase=after_5s host_after_ns=HOST_AFTER_NS_PLACEHOLDER guest_date_ns=${{guest_date_ns_5}} guest_uptime_s=${{guest_uptime_5}}"
echo "EXEC label=${{label}} status=ok roundtrip=completed"
"#
);
let out = vm
.exec_builder()
.argv(["/bin/sh", "-c", &script])
.output()?;
let host_after = host_ns();
let stdout = String::from_utf8_lossy(&out.stdout)
.replace("HOST_AFTER_NS_PLACEHOLDER", &host_after.to_string());
let stderr = String::from_utf8_lossy(&out.stderr).to_string();
let success = out.success();
vm.stop().ok();
if !success {
return Err(
format!("child {label} exec failed: stdout={stdout:?} stderr={stderr:?}").into(),
);
}
let uuid = stdout
.lines()
.find(|line| line.starts_with("IDENTITY "))
.and_then(|line| {
line.split_whitespace()
.find(|part| part.starts_with("uuid="))
})
.unwrap_or("uuid=<missing>")
.trim_start_matches("uuid=")
.to_owned();
let urandom = stdout
.lines()
.find(|line| line.starts_with("IDENTITY "))
.and_then(|line| {
line.split_whitespace()
.find(|part| part.starts_with("urandom16="))
})
.unwrap_or("urandom16=<missing>")
.trim_start_matches("urandom16=")
.to_owned();
Ok((stdout, uuid, urandom))
}
let base_dir = required_env("SUPERMACHINE_FORK_HYGIENE_BASE_SNAPSHOT")?;
let workdir = PathBuf::from(required_env("SUPERMACHINE_FORK_HYGIENE_WORKDIR")?);
if !Path::new(&base_dir).is_dir() {
return Err(format!("base snapshot dir does not exist: {base_dir}").into());
}
if workdir.exists() {
std::fs::remove_dir_all(&workdir)?;
}
std::fs::create_dir_all(&workdir)?;
println!(
"FORK_HYGIENE_PROBE start pid={} base_snapshot={} workdir={}",
process::id(),
base_dir,
workdir.display()
);
let base = Image::from_snapshot(&base_dir)?;
println!("STEP restore_base_for_diff status=start");
let vm = base.start(&VmConfig::new())?;
let marker = format!("fork-hygiene-node-{}", process::id());
let out = vm
.exec_builder()
.argv(["/bin/sh", "-c", &format!("echo {marker} >/tmp/supermachine-fork-hygiene-marker && sync && cat /tmp/supermachine-fork-hygiene-marker")])
.output()?;
if !out.success() {
return Err(format!(
"failed to seed diff node: {}",
String::from_utf8_lossy(&out.stderr)
)
.into());
}
println!(
"STEP restore_base_for_diff status=ok marker={}",
String::from_utf8_lossy(&out.stdout).trim()
);
let diff_dir = workdir.join("diff-node");
println!(
"STEP capture_diff_node status=start path={}",
diff_dir.display()
);
let node = vm.snapshot_diff(&diff_dir, &base)?;
println!(
"STEP capture_diff_node status=ok path={}",
diff_dir.display()
);
println!("STEP restore_two_children_concurrently status=start");
let node_a = node.clone();
let node_b = node;
let a = std::thread::spawn(move || run_child("child_a", node_a));
let b = std::thread::spawn(move || run_child("child_b", node_b));
let (out_a, uuid_a, rng_a) = a.join().map_err(|_| "child_a thread panicked")??;
let (out_b, uuid_b, rng_b) = b.join().map_err(|_| "child_b thread panicked")??;
print!("{out_a}");
print!("{out_b}");
println!(
"COMPARE uuid_equal={} urandom16_equal={}",
uuid_a == uuid_b,
rng_a == rng_b
);
println!("STEP restore_two_children_concurrently status=ok");
println!("FORK_HYGIENE_PROBE result=pass");
Ok(())
}
#[cfg(not(all(target_os = "linux", target_arch = "x86_64")))]
fn main() {
eprintln!("_fork_hygiene_probe is Linux/x86_64 only");
}