From 78885bb1d8ee66ec5d30b2c268c76ff017bb314c Mon Sep 17 00:00:00 2001 From: Ryan Breen Date: Fri, 13 Feb 2026 06:52:46 -0500 Subject: [PATCH] feat: add /proc/breenix/testing and update ARM64 test suite paths Add /proc/breenix/testing procfs entry that exposes the kernel's `testing` feature flag (returns "1" when enabled, "0" otherwise). The shell reads this at startup to conditionally include /usr/local/test/bin in PATH, keeping test binaries out of the interactive shell experience in non-testing builds. Update the ARM64 test suite runner to discover test binaries from /usr/local/test/bin/ and patch the kernel source with the new path. Co-Authored-By: Ryan Breen Co-Authored-By: Claude Opus 4.6 --- docker/qemu/run-aarch64-test-suite.sh | 6 ++-- kernel/src/fs/procfs/mod.rs | 45 ++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/docker/qemu/run-aarch64-test-suite.sh b/docker/qemu/run-aarch64-test-suite.sh index 7502253f..01632b86 100755 --- a/docker/qemu/run-aarch64-test-suite.sh +++ b/docker/qemu/run-aarch64-test-suite.sh @@ -38,7 +38,7 @@ if [ "$1" = "--all" ]; then apk add --no-cache e2fsprogs >/dev/null 2>&1 mkdir -p /mnt/ext2 mount -o ro /ext2.img /mnt/ext2 - ls /mnt/ext2/bin/ | grep -E "_test$" | sort + ls /mnt/ext2/usr/local/test/bin/ 2>/dev/null | grep -E "_test$|^test_" | sort ' 2>/dev/null) elif [ -n "$1" ]; then TESTS="$@" @@ -95,12 +95,12 @@ with open(kernel_src, 'r') as f: # Replace the path in run_userspace_from_ext2 call (handles both init_shell and bsh) content = re.sub( r'run_userspace_from_ext2\("/bin/(init_shell|bsh)"\)', - f'run_userspace_from_ext2("/bin/{test_name}")', + f'run_userspace_from_ext2("/usr/local/test/bin/{test_name}")', content ) with open(kernel_src, 'w') as f: f.write(content) -print(f"Modified kernel to load: /bin/{test_name}") +print(f"Modified kernel to load: /usr/local/test/bin/{test_name}") PYTHON # Build (with testing feature to enable exec() and other test syscalls) diff --git a/kernel/src/fs/procfs/mod.rs b/kernel/src/fs/procfs/mod.rs index 59e0622f..468a0540 100644 --- a/kernel/src/fs/procfs/mod.rs +++ b/kernel/src/fs/procfs/mod.rs @@ -74,6 +74,10 @@ pub enum ProcEntryType { CowInfo, /// /proc/mounts - mounted filesystems Mounts, + /// /proc/breenix - breenix info directory + BreenixDir, + /// /proc/breenix/testing - whether testing mode is active + BreenixTesting, /// /proc/[pid] - per-process directory (dynamic, not registered) PidDir(u64), /// /proc/[pid]/status - per-process status (dynamic, not registered) @@ -101,6 +105,8 @@ impl ProcEntryType { ProcEntryType::Stat => "stat", ProcEntryType::CowInfo => "cowinfo", ProcEntryType::Mounts => "mounts", + ProcEntryType::BreenixDir => "breenix", + ProcEntryType::BreenixTesting => "testing", ProcEntryType::PidDir(_) => "pid", ProcEntryType::PidStatus(_) => "status", } @@ -126,6 +132,8 @@ impl ProcEntryType { ProcEntryType::Stat => "/proc/stat", ProcEntryType::CowInfo => "/proc/cowinfo", ProcEntryType::Mounts => "/proc/mounts", + ProcEntryType::BreenixDir => "/proc/breenix", + ProcEntryType::BreenixTesting => "/proc/breenix/testing", // Dynamic entries don't have static paths ProcEntryType::PidDir(_) => "/proc/", ProcEntryType::PidStatus(_) => "/proc//status", @@ -153,6 +161,8 @@ impl ProcEntryType { ProcEntryType::Stat => 6, ProcEntryType::CowInfo => 7, ProcEntryType::Mounts => 8, + ProcEntryType::BreenixDir => 200, + ProcEntryType::BreenixTesting => 201, ProcEntryType::PidDir(pid) => 10000 + pid, ProcEntryType::PidStatus(pid) => 20000 + pid, } @@ -160,7 +170,10 @@ impl ProcEntryType { /// Check if this is a directory pub fn is_directory(&self) -> bool { - matches!(self, ProcEntryType::TraceDir | ProcEntryType::PidDir(_)) + matches!( + self, + ProcEntryType::TraceDir | ProcEntryType::BreenixDir | ProcEntryType::PidDir(_) + ) } } @@ -215,6 +228,10 @@ pub fn init() { procfs.entries.push(ProcEntry::new(ProcEntryType::CowInfo)); procfs.entries.push(ProcEntry::new(ProcEntryType::Mounts)); + // Register /proc/breenix directory and entries + procfs.entries.push(ProcEntry::new(ProcEntryType::BreenixDir)); + procfs.entries.push(ProcEntry::new(ProcEntryType::BreenixTesting)); + // Register /proc/trace directory and entries procfs.entries.push(ProcEntry::new(ProcEntryType::TraceDir)); procfs.entries.push(ProcEntry::new(ProcEntryType::TraceEnable)); @@ -304,6 +321,7 @@ pub fn list_entries() -> Vec { | ProcEntryType::TraceBuffer | ProcEntryType::TraceCounters | ProcEntryType::TraceProviders + | ProcEntryType::BreenixTesting )) .map(|e| String::from(e.entry_type.name())) .collect() @@ -341,6 +359,17 @@ pub fn list_trace_entries() -> Vec { .collect() } +/// List entries in the /proc/breenix directory +pub fn list_breenix_entries() -> Vec { + let procfs = PROCFS.lock(); + procfs + .entries + .iter() + .filter(|e| matches!(e.entry_type, ProcEntryType::BreenixTesting)) + .map(|e| String::from(e.entry_type.name())) + .collect() +} + /// Check if procfs is initialized pub fn is_initialized() -> bool { PROCFS.lock().initialized @@ -373,6 +402,20 @@ pub fn read_entry(entry_type: ProcEntryType) -> Result { ProcEntryType::Stat => Ok(generate_stat()), ProcEntryType::CowInfo => Ok(generate_cowinfo()), ProcEntryType::Mounts => Ok(generate_mounts()), + ProcEntryType::BreenixDir => { + // Directory listing + Ok(String::from("testing\n")) + } + ProcEntryType::BreenixTesting => { + #[cfg(feature = "testing")] + { + Ok(String::from("1\n")) + } + #[cfg(not(feature = "testing"))] + { + Ok(String::from("0\n")) + } + } ProcEntryType::PidDir(pid) => Ok(generate_pid_dir(pid)), ProcEntryType::PidStatus(pid) => Ok(generate_pid_status(pid)), }