support running shebang executables

This commit is contained in:
Jianfeng Jiang
2023-03-07 16:10:15 +08:00
committed by Tate, Hongliang Tian
parent a084c3b687
commit 57297e0cd5
3 changed files with 81 additions and 17 deletions

View File

@ -25,11 +25,6 @@ use crate::{
}; };
use process::Process; use process::Process;
use crate::process::{
process_filter::ProcessFilter,
wait::{wait_child_exit, WaitOptions},
};
extern crate alloc; extern crate alloc;
extern crate lru; extern crate lru;
#[macro_use] #[macro_use]

View File

@ -11,14 +11,15 @@ use self::signal::sig_queues::SigQueues;
use self::signal::signals::kernel::KernelSignal; use self::signal::signals::kernel::KernelSignal;
use self::status::ProcessStatus; use self::status::ProcessStatus;
use crate::fs::file_table::FileTable; use crate::fs::file_table::FileTable;
use crate::fs::fs_resolver::FsResolver; use crate::fs::fs_resolver::{FsPath, FsResolver};
use crate::fs::utils::AccessMode;
use crate::prelude::*; use crate::prelude::*;
use crate::rights::Full; use crate::rights::Full;
use crate::thread::{thread_table, Thread}; use crate::thread::{thread_table, Thread};
use crate::tty::get_n_tty; use crate::tty::get_n_tty;
use crate::vm::vmar::Vmar; use crate::vm::vmar::Vmar;
use alloc::string::String;
use jinux_frame::sync::WaitQueue; use jinux_frame::sync::WaitQueue;
use jinux_frame::task::Task;
pub mod clone; pub mod clone;
pub mod elf; pub mod elf;
@ -386,3 +387,77 @@ impl Process {
pub fn get_init_process() -> Option<Arc<Process>> { pub fn get_init_process() -> Option<Arc<Process>> {
process_table::pid_to_process(INIT_PROCESS_PID) process_table::pid_to_process(INIT_PROCESS_PID)
} }
/// Set up root vmar for an executable.
/// About recursion_limit: recursion limit is used to limit th recursion depth of shebang executables.
/// If the interpreter program(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 program.
/// I guess for most cases, setting the recursion_limit as 1 should be enough.
/// because the interpreter game is usually an elf binary(e.g., /bin/bash)
pub fn setup_root_vmar(
executable_path: String,
argv: Vec<CString>,
envp: Vec<CString>,
fs_resolver: &FsResolver,
root_vmar: Vmar<Full>,
recursion_limit: usize,
) -> Result<()> {
use crate::fs::fs_resolver::AT_FDCWD;
let fs_path = FsPath::new(AT_FDCWD, &executable_path)?;
let file = fs_resolver.open(&fs_path, AccessMode::O_RDONLY as u32, 0)?;
// read the first page of file header
let mut file_header_buffer = [0u8; PAGE_SIZE];
file.read(&mut file_header_buffer)?;
if recursion_limit > 0
&& file_header_buffer.starts_with(b"!#")
&& file_header_buffer.contains(&b'\n')
{
return set_up_root_vmar_for_shebang(
argv,
envp,
&file_header_buffer,
fs_resolver,
root_vmar,
recursion_limit,
);
}
todo!()
}
fn set_up_root_vmar_for_shebang(
argv: Vec<CString>,
envp: Vec<CString>,
file_header_buffer: &[u8],
fs_resolver: &FsResolver,
root_vmar: Vmar<Full>,
recursion_limit: usize,
) -> Result<()> {
let first_line_len = file_header_buffer.iter().position(|&c| c == b'\n').unwrap();
// skip !#
let shebang_header = &file_header_buffer[2..first_line_len];
let mut shebang_argv = Vec::new();
for arg in shebang_header.split(|&c| c == b' ') {
let arg = CString::new(arg)?;
shebang_argv.push(arg);
}
if shebang_argv.len() != 1 {
return_errno_with_message!(
Errno::EINVAL,
"One and only one intpreter program should be specified"
);
}
for origin_arg in argv.into_iter() {
shebang_argv.push(origin_arg);
}
use alloc::string::ToString;
let shebang_path = shebang_argv[0].to_str()?.to_string();
setup_root_vmar(
shebang_path,
shebang_argv,
envp,
fs_resolver,
root_vmar,
recursion_limit - 1,
)
}

View File

@ -4,14 +4,12 @@ use crate::prelude::*;
use super::{allocate_tid, status::ThreadStatus, thread_table, Thread}; use super::{allocate_tid, status::ThreadStatus, thread_table, Thread};
/// This struct is used to mark a thread is a kernel thread /// The inner data of a kernel thread
pub struct KernelThread; pub struct KernelThread;
pub trait KernelThreadExt { pub trait KernelThreadExt {
/// whether the thread is a kernel thread
fn is_kernel_thread(&self) -> bool;
/// get the kernel_thread structure /// get the kernel_thread structure
fn kernel_thread(&self) -> &KernelThread; fn as_kernel_thread(&self) -> Option<&KernelThread>;
/// create a new kernel thread structure, **NOT** run the thread. /// create a new kernel thread structure, **NOT** run the thread.
fn new_kernel_thread<F>(task_fn: F) -> Arc<Thread> fn new_kernel_thread<F>(task_fn: F) -> Arc<Thread>
where where
@ -30,12 +28,8 @@ pub trait KernelThreadExt {
} }
impl KernelThreadExt for Thread { impl KernelThreadExt for Thread {
fn is_kernel_thread(&self) -> bool { fn as_kernel_thread(&self) -> Option<&KernelThread> {
self.data().downcast_ref::<KernelThread>().is_some() self.data().downcast_ref::<KernelThread>()
}
fn kernel_thread(&self) -> &KernelThread {
self.data().downcast_ref::<KernelThread>().unwrap()
} }
fn new_kernel_thread<F>(task_fn: F) -> Arc<Self> fn new_kernel_thread<F>(task_fn: F) -> Arc<Self>