-
Notifications
You must be signed in to change notification settings - Fork 308
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Refactor init into test-distro
The init module contains a small init system for running our integration tests against a kernel. While we don't need a full-blown linux distro, we do need some utilities. Once such utility is `modprobe` which allows us to load kernel modules. Rather than create a new module for this utility, I've instead refactored `init` into `test-distro` which is a module that contains multiple binaries. The xtask code has been adjusted to ensure these binaries are inserted into the correct places in our cpio archive, as well as bringing in the kernel modules. Signed-off-by: Dave Tucker <[email protected]>
- Loading branch information
1 parent
921e457
commit f4cd4f9
Showing
12 changed files
with
418 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
[package] | ||
name = "test-distro" | ||
version = "0.1.0" | ||
publish = false | ||
authors.workspace = true | ||
license.workspace = true | ||
repository.workspace = true | ||
homepage.workspace = true | ||
edition.workspace = true | ||
|
||
[[bin]] | ||
name = "init" | ||
path = "src/init.rs" | ||
|
||
[[bin]] | ||
name = "modprobe" | ||
path = "src/modprobe.rs" | ||
|
||
[[bin]] | ||
name = "depmod" | ||
path = "src/depmod.rs" | ||
|
||
[dependencies] | ||
anyhow = { workspace = true, features = ["std"] } | ||
object = { workspace = true, features = ["elf", "read_core", "std"] } | ||
clap = { workspace = true, default-features = true, features = ["derive"] } | ||
nix = { workspace = true, features = [ | ||
"user", | ||
"fs", | ||
"mount", | ||
"reboot", | ||
"kmod", | ||
"feature", | ||
] } | ||
glob = { workspace = true } | ||
xz2 = { workspace = true } | ||
walkdir = { workspace = true } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
//! depmod is used to build the modules.alias file to assist with loading | ||
//! kernel modules. | ||
//! | ||
//! This implementation is incredibly naive and is only designed to work within | ||
//! the constraints of the test environment. Not for production use. | ||
use std::{ | ||
fs::File, | ||
io::{BufWriter, Read as _, Write as _}, | ||
}; | ||
|
||
use object::{Object, ObjectSection, ObjectSymbol}; | ||
use test_distro::resolve_modules_dir; | ||
use walkdir::WalkDir; | ||
|
||
fn main() { | ||
let modules_dir = resolve_modules_dir().expect("Failed to resolve modules dir"); | ||
|
||
let output = std::fs::OpenOptions::new() | ||
.create(true) | ||
.write(true) | ||
.truncate(true) | ||
.open(modules_dir.join("modules.alias")) | ||
.expect("Failed to open modules.alias file"); | ||
|
||
for entry in WalkDir::new(modules_dir) { | ||
let entry = entry.expect("Failed to read entry"); | ||
if entry.file_type().is_file() { | ||
let path = entry.path(); | ||
if let Some(extension) = path.extension() { | ||
if extension != "ko" && extension != "xz" { | ||
continue; | ||
} | ||
let mut f = File::open(path).expect("Failed to open module file"); | ||
let mut contents: Vec<u8> = Vec::new(); | ||
f.read_to_end(&mut contents).expect("read"); | ||
|
||
if extension == "xz" { | ||
let mut decompressed = Vec::new(); | ||
xz2::read::XzDecoder::new(&contents[..]) | ||
.read_to_end(&mut decompressed) | ||
.expect("Failed to decompress module"); | ||
contents = decompressed; | ||
} | ||
|
||
let obj = | ||
object::read::File::parse(&*contents).expect("Failed to parse object file"); | ||
|
||
let module_name = path.file_stem().unwrap().to_string_lossy(); | ||
// Remove the .ko extension if this was compressed | ||
let module_name = module_name.replace(".ko", ""); | ||
|
||
let (section_idx, data) = obj | ||
.sections() | ||
.filter_map(|s| { | ||
if let Ok(name) = s.name() { | ||
if name == ".modinfo" { | ||
if let Ok(data) = s.data() { | ||
return Some((s.index(), data)); | ||
} | ||
} | ||
} | ||
None | ||
}) | ||
.next() | ||
.expect("Failed to find .modinfo section"); | ||
|
||
let aliases = obj | ||
.symbols() | ||
.filter_map(|s| { | ||
if let Ok(name) = s.name() { | ||
if name.contains("alias") && s.section_index() == Some(section_idx) { | ||
let start = s.address() as usize; | ||
let end = start + s.size() as usize; | ||
let sym_data = &data[start..end]; | ||
let cstr = std::ffi::CStr::from_bytes_with_nul(sym_data).ok()?; | ||
let sym_str = cstr.to_string_lossy(); | ||
let alias = sym_str.replace("alias=", ""); | ||
return Some(alias); | ||
} | ||
} | ||
None | ||
}) | ||
.collect::<Vec<_>>(); | ||
|
||
let mut f = BufWriter::new(&output); | ||
for alias in aliases { | ||
f.write_all(format!("alias {} {}\n", alias, module_name).as_bytes()) | ||
.expect("write"); | ||
} | ||
f.flush().expect("flush"); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
use std::path::PathBuf; | ||
|
||
use nix::sys::utsname::uname; | ||
|
||
// Kernel modules are in `/lib/modules`. | ||
// They may be in the root of this directory, | ||
// or in subdirectory named after the kernel release. | ||
pub fn resolve_modules_dir() -> anyhow::Result<PathBuf> { | ||
let mut modules_dir = PathBuf::from("/lib/modules"); | ||
|
||
if !modules_dir.join("kernel").exists() { | ||
let utsname = uname().expect("Failed to get uname"); | ||
let release = utsname.release(); | ||
if modules_dir.join(release).exists() { | ||
modules_dir = modules_dir.join(release); | ||
} else { | ||
anyhow::bail!( | ||
"No kernel modules found for release: {}", | ||
release.to_string_lossy() | ||
); | ||
} | ||
} | ||
Ok(modules_dir) | ||
} |
Oops, something went wrong.