use std::io::{BufRead, BufReader};
use std::path::{Path, PathBuf};
use std::process::Command;
mod common;
fn main() {
if cfg!(target_os = "netbsd") {
return;
}
if std::env::var(VAR).is_err() {
match parent() {
Ok(()) => {
println!("test result: ok");
}
Err(EarlyExit::IgnoreTest) => {
println!("test result: ignored");
}
Err(EarlyExit::IoError(e)) => {
println!("{} parent encountered IoError: {:?}", file!(), e);
panic!();
}
}
} else {
child().unwrap();
}
}
const VAR: &str = "__THE_TEST_YOU_ARE_LUKE";
#[derive(Debug)]
enum EarlyExit {
IgnoreTest,
IoError(std::io::Error),
}
impl From<std::io::Error> for EarlyExit {
fn from(e: std::io::Error) -> Self {
EarlyExit::IoError(e)
}
}
fn parent() -> Result<(), EarlyExit> {
if common::cannot_reexec_the_test() {
return Err(EarlyExit::IgnoreTest);
}
let me = std::env::current_exe().unwrap();
let ld_so = find_interpreter(&me)?;
let result = Command::new(ld_so).env(VAR, "1").arg(&me).output().unwrap();
if result.status.success() {
return Ok(());
}
println!("stdout:\n{}", String::from_utf8_lossy(&result.stdout));
println!("stderr:\n{}", String::from_utf8_lossy(&result.stderr));
println!("code: {}", result.status);
panic!();
}
fn child() -> Result<(), EarlyExit> {
let bt = backtrace::Backtrace::new();
println!("{bt:?}");
let mut found_my_name = false;
let my_filename = file!();
'frames: for frame in bt.frames() {
let symbols = frame.symbols();
if symbols.is_empty() {
continue;
}
for sym in symbols {
if let Some(filename) = sym.filename() {
if filename.ends_with(my_filename) {
found_my_name = true;
break 'frames;
}
}
}
}
assert!(found_my_name);
Ok(())
}
fn find_interpreter(me: &Path) -> Result<PathBuf, EarlyExit> {
let result = Command::new("readelf")
.arg("-l")
.arg(me)
.output()
.map_err(|_| EarlyExit::IgnoreTest)?;
if result.status.success() {
let r = BufReader::new(&result.stdout[..]);
for line in r.lines() {
let line = line?;
let line = line.trim();
let prefix = "[Requesting program interpreter: ";
if let Some((_, suffix)) = line.split_once(prefix) {
if let Some((found_path, _)) = suffix.rsplit_once("]") {
return Ok(found_path.into());
}
}
}
}
Err(EarlyExit::IgnoreTest)
}