asterinas/services/libs/jinux-std/src/process/program_loader/mod.rs

76 lines
2.7 KiB
Rust
Raw Normal View History

2023-03-14 07:35:38 +00:00
pub mod elf;
mod shebang;
use crate::fs::fs_resolver::{FsPath, FsResolver, AT_FDCWD};
2023-06-13 02:13:00 +00:00
use crate::fs::utils::Dentry;
2023-03-14 07:35:38 +00:00
use crate::prelude::*;
use crate::vm::vmar::Vmar;
use jinux_rights::Full;
2023-03-14 07:35:38 +00:00
use self::elf::{load_elf_to_root_vmar, ElfLoadInfo};
use self::shebang::parse_shebang_line;
/// Load an executable to root vmar, including loading programe image, preparing heap and stack,
/// initializing argv, envp and aux tables.
/// About recursion_limit: recursion limit is used to limit th recursion depth of shebang executables.
/// If the interpreter(the program behind #!) of shebang executable is also a shebang,
/// then it will trigger recursion. We will try to setup root vmar for the interpreter.
/// I guess for most cases, setting the recursion_limit as 1 should be enough.
/// because the interpreter is usually an elf binary(e.g., /bin/bash)
pub fn load_program_to_root_vmar(
root_vmar: &Vmar<Full>,
2023-06-13 02:13:00 +00:00
elf_file: Arc<Dentry>,
2023-03-14 07:35:38 +00:00
argv: Vec<CString>,
envp: Vec<CString>,
fs_resolver: &FsResolver,
recursion_limit: usize,
) -> Result<(String, ElfLoadInfo)> {
2023-03-31 05:52:00 +00:00
let abs_path = elf_file.abs_path();
let vnode = elf_file.vnode();
2023-03-14 07:35:38 +00:00
let file_header = {
// read the first page of file header
2023-03-29 03:35:02 +00:00
let mut file_header_buffer = Box::new([0u8; PAGE_SIZE]);
2023-03-31 05:52:00 +00:00
vnode.read_at(0, &mut *file_header_buffer)?;
2023-03-14 07:35:38 +00:00
file_header_buffer
};
2023-03-29 03:35:02 +00:00
if let Some(mut new_argv) = parse_shebang_line(&*file_header)? {
2023-03-14 07:35:38 +00:00
if recursion_limit == 0 {
return_errno_with_message!(Errno::ELOOP, "the recursieve limit is reached");
2023-03-14 07:35:38 +00:00
}
new_argv.extend_from_slice(&argv);
2023-06-13 02:13:00 +00:00
let interpreter = {
let filename = new_argv[0].to_str()?.to_string();
let fs_path = FsPath::new(AT_FDCWD, &filename)?;
fs_resolver.lookup(&fs_path)?
};
check_executable_file(&interpreter)?;
2023-03-14 07:35:38 +00:00
return load_program_to_root_vmar(
root_vmar,
interpreter,
new_argv,
envp,
fs_resolver,
recursion_limit - 1,
);
}
2023-03-31 05:52:00 +00:00
let elf_load_info =
load_elf_to_root_vmar(root_vmar, &*file_header, elf_file, fs_resolver, argv, envp)?;
Ok((abs_path, elf_load_info))
2023-03-14 07:35:38 +00:00
}
pub fn check_executable_file(dentry: &Arc<Dentry>) -> Result<()> {
if dentry.inode_type().is_directory() {
return_errno_with_message!(Errno::EISDIR, "the file is a directory");
}
if !dentry.inode_type().is_reguler_file() {
return_errno_with_message!(Errno::EACCES, "the dentry is not a regular file");
}
if !dentry.inode_mode().is_executable() {
return_errno_with_message!(Errno::EACCES, "the dentry is not executable");
}
Ok(())
}