102 lines
3.6 KiB
Rust
102 lines
3.6 KiB
Rust
use alloc::borrow::ToOwned;
|
|
use alloc::vec::Vec;
|
|
|
|
use syscall::{Error, EINTR};
|
|
use syscall::flag::{O_CLOEXEC, O_RDONLY};
|
|
|
|
use redox_exec::*;
|
|
|
|
pub fn main() -> ! {
|
|
let initfs_length;
|
|
|
|
let envs = {
|
|
let mut env = [0_u8; 4096];
|
|
|
|
let fd = FdGuard::new(syscall::open("sys:env", O_RDONLY).expect("bootstrap: failed to open env"));
|
|
let bytes_read = syscall::read(*fd, &mut env).expect("bootstrap: failed to read env");
|
|
|
|
if bytes_read >= env.len() {
|
|
// TODO: Handle this, we can allocate as much as we want in theory.
|
|
panic!("env is too large");
|
|
}
|
|
let env = &mut env[..bytes_read];
|
|
|
|
let raw_iter = || env.split(|c| *c == b'\n').filter(|var| !var.is_empty());
|
|
|
|
let mut initfs_length_opt = None;
|
|
|
|
for var in raw_iter() {
|
|
let equal_sign = var.iter().position(|c| *c == b'=').expect("malformed environment variable");
|
|
let name = &var[..equal_sign];
|
|
let value = &var[equal_sign + 1..];
|
|
|
|
match name {
|
|
b"INITFS_LENGTH" => initfs_length_opt = core::str::from_utf8(value).ok().and_then(|s| usize::from_str_radix(s, 16).ok()),
|
|
|
|
_ => continue,
|
|
}
|
|
}
|
|
initfs_length = initfs_length_opt.expect("missing INITFS_LENGTH");
|
|
|
|
let iter = || raw_iter().filter(|var| !var.starts_with(b"INITFS_"));
|
|
|
|
iter().map(|var| var.to_owned()).collect::<Vec<_>>()
|
|
};
|
|
|
|
extern {
|
|
// The linker script will define this as the location of the initfs header.
|
|
static __initfs_header: u8;
|
|
}
|
|
|
|
unsafe {
|
|
// Creating a reference to NULL is UB. Mask the UB for now using black_box.
|
|
// FIXME use a raw pointer and inline asm for reading instead for the initfs header.
|
|
spawn_initfs(core::ptr::addr_of!(__initfs_header), initfs_length);
|
|
}
|
|
const CWD: &[u8] = b"/scheme/initfs";
|
|
let extrainfo = redox_exec::ExtraInfo {
|
|
cwd: Some(CWD),
|
|
};
|
|
|
|
let path = "/scheme/initfs/bin/init";
|
|
let total_args_envs_auxvpointee_size = path.len() + 1 + envs.len() + envs.iter().map(|v| v.len()).sum::<usize>() + CWD.len() + 1;
|
|
|
|
let image_file = FdGuard::new(syscall::open(path, O_RDONLY).expect("failed to open init"));
|
|
let open_via_dup = FdGuard::new(syscall::open("thisproc:current/open_via_dup", 0).expect("failed to open open_via_dup"));
|
|
let memory = FdGuard::new(syscall::open("memory:", 0).expect("failed to open memory"));
|
|
|
|
fexec_impl(image_file, open_via_dup, &memory, path.as_bytes(), [path], envs.iter(), total_args_envs_auxvpointee_size, &extrainfo, None).expect("failed to execute init");
|
|
|
|
unreachable!()
|
|
}
|
|
|
|
unsafe fn spawn_initfs(initfs_start: *const u8, initfs_length: usize) {
|
|
let read = syscall::open("pipe:", O_CLOEXEC).expect("failed to open sync read pipe");
|
|
|
|
// The write pipe will not inherit O_CLOEXEC, but is closed by the daemon later.
|
|
let write = syscall::dup(read, b"write").expect("failed to open sync write pipe");
|
|
|
|
match redox_exec::fork_impl() {
|
|
Err(err) => {
|
|
panic!("Failed to fork in order to start initfs daemon: {}", err);
|
|
}
|
|
// Continue serving the scheme as the child.
|
|
Ok(0) => {
|
|
let _ = syscall::close(read);
|
|
}
|
|
// Return in order to execute init, as the parent.
|
|
Ok(_) => {
|
|
let _ = syscall::close(write);
|
|
loop {
|
|
match syscall::read(read, &mut [0]) {
|
|
Err(Error { errno: EINTR }) => continue,
|
|
_ => break,
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
crate::initfs::run(core::slice::from_raw_parts(initfs_start, initfs_length), write);
|
|
}
|