support running busybox shell

This commit is contained in:
Jianfeng Jiang
2022-11-21 19:09:23 +08:00
parent 9cf8fe1777
commit f3ab8219bc
32 changed files with 794 additions and 184 deletions

41
src/Cargo.lock generated
View File

@ -8,6 +8,12 @@ version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b"
[[package]]
name = "arrayvec"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "autocfg"
version = "1.1.0"
@ -155,7 +161,9 @@ dependencies = [
"kxos-typeflags-util",
"kxos-virtio",
"lazy_static",
"ringbuffer",
"spin 0.9.4",
"vte",
"xmas-elf",
]
@ -253,6 +261,12 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "ringbuffer"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "310a2514cb46bb500a2f2ad70c79c51c5a475cc23faa245d2c675faabe889370"
[[package]]
name = "runner-utils"
version = "0.0.2"
@ -353,12 +367,39 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
[[package]]
name = "utf8parse"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
[[package]]
name = "volatile"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ca98349dda8a60ae74e04fd90c7fb4d6a4fbe01e6d3be095478aa0b76f6c0c"
[[package]]
name = "vte"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983"
dependencies = [
"arrayvec",
"utf8parse",
"vte_generate_state_changes",
]
[[package]]
name = "vte_generate_state_changes"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
name = "wait-timeout"
version = "0.2.0"

View File

@ -3,13 +3,23 @@ use spin::Mutex;
use uart_16550::SerialPort;
lazy_static! {
pub(crate) static ref SERIAL: Mutex<SerialPort> = {
pub static ref SERIAL: Mutex<SerialPort> = {
let mut serial_port = unsafe { SerialPort::new(0x3F8) };
serial_port.init();
Mutex::new(serial_port)
};
}
/// read a char from the keyboard input.
/// FIXME: this function should **NOT** block. If no char receives, this function should return None immediately.
/// However, the receive function on SERIAL will block until a char is received, which will block the whole kernel.
/// A more correct implementation should be added once interrupt is ready. We should register the kerboard interrupt
/// handler to wake up foreground processes which wait on IOEVENTS.
pub fn receive_char() -> Option<u8> {
let byte = SERIAL.lock().receive();
Some(byte)
}
#[doc(hidden)]
pub fn _print(args: ::core::fmt::Arguments) {
use core::fmt::Write;

View File

@ -40,6 +40,7 @@ use bootloader::{
boot_info::{FrameBuffer, MemoryRegionKind},
BootInfo,
};
pub use device::serial::receive_char;
pub use mm::address::{align_down, align_up, is_aligned, virt_to_phys};
pub use trap::{allocate_irq, IrqAllocateHandle, TrapFrame};
use trap::{IrqCallbackHandle, IrqLine};

View File

@ -1,6 +1,5 @@
use core::sync::atomic::{AtomicBool, Ordering};
use crate::prelude::*;
use alloc::{collections::VecDeque, sync::Arc};
use bitflags::bitflags;
use spin::mutex::Mutex;

View File

@ -19,8 +19,10 @@ xmas-elf = "0.8.0"
# goblin = {version= "0.5.3", default-features = false, features = ["elf64"]}
# data-structures
bitflags = "1.3"
ringbuffer = "0.10.0"
spin = "0.9.4"
vte = "0.10"
[dependencies.lazy_static]
version = "1.0"

View File

@ -1,15 +1,5 @@
use crate::prelude::*;
use crate::define_fcntl_cmd;
define_fcntl_cmd! {
F_DUPFD = 0,
F_GETFD = 1,
F_SETFD = 2,
F_DUPFD_CLOEXEC = 1030
}
#[macro_export]
macro_rules! define_fcntl_cmd {
($($name: ident = $value: expr),*) => {
#[repr(i32)]
@ -34,3 +24,10 @@ macro_rules! define_fcntl_cmd {
}
}
}
define_fcntl_cmd! {
F_DUPFD = 0,
F_GETFD = 1,
F_SETFD = 2,
F_DUPFD_CLOEXEC = 1030
}

View File

@ -1,5 +1,6 @@
use crate::prelude::*;
use core::{any::Any, fmt::Debug};
use crate::tty::get_console;
use core::any::Any;
use super::events::IoEvents;
use super::ioctl::IoctlCmd;
@ -7,7 +8,7 @@ use super::ioctl::IoctlCmd;
pub type FileDescripter = i32;
/// The basic operations defined on a file
pub trait File: Send + Sync + Debug + Any {
pub trait File: Send + Sync + Any {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
panic!("read unsupported");
}
@ -16,8 +17,15 @@ pub trait File: Send + Sync + Debug + Any {
panic!("write unsupported");
}
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
panic!("ioctl unsupported");
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
match cmd {
IoctlCmd::TCGETS => {
// FIXME: only a work around
let tty = get_console();
tty.ioctl(cmd, arg)
}
_ => panic!("Ioctl unsupported"),
}
}
fn poll(&self) -> IoEvents {

View File

@ -5,7 +5,7 @@ use super::{
stdio::{Stderr, Stdin, Stdout, FD_STDERR, FD_STDIN, FD_STDOUT},
};
#[derive(Debug, Clone)]
#[derive(Clone)]
pub struct FileTable {
table: BTreeMap<FileDescripter, Arc<dyn File>>,
}
@ -19,9 +19,12 @@ impl FileTable {
pub fn new_with_stdio() -> Self {
let mut table = BTreeMap::new();
table.insert(FD_STDIN, Arc::new(Stdin) as Arc<dyn File>);
table.insert(FD_STDOUT, Arc::new(Stdout) as Arc<dyn File>);
table.insert(FD_STDERR, Arc::new(Stderr) as Arc<dyn File>);
let stdin = Stdin::new_with_default_console();
let stdout = Stdout::new_with_default_console();
let stderr = Stderr::new_with_default_console();
table.insert(FD_STDIN, Arc::new(stdin) as Arc<dyn File>);
table.insert(FD_STDOUT, Arc::new(stdout) as Arc<dyn File>);
table.insert(FD_STDERR, Arc::new(stderr) as Arc<dyn File>);
Self { table }
}
@ -47,6 +50,16 @@ impl FileTable {
self.table.iter().map(|(fd, _)| fd.clone()).max().unwrap()
}
pub fn insert(&mut self, item: Arc<dyn File>) -> FileDescripter {
let fd = self.max_fd() + 1;
self.table.insert(fd, item);
fd
}
pub fn close_file(&mut self, fd: FileDescripter) {
self.table.remove(&fd);
}
pub fn get_file(&self, fd: FileDescripter) -> Option<&Arc<dyn File>> {
self.table.get(&fd)
}

View File

@ -1,22 +1,5 @@
pub mod termio;
use crate::define_ioctl_cmd;
use crate::prelude::*;
define_ioctl_cmd! {
// Get terminal attributes
TCGETS = 0x5401,
TCSETS = 0x5402,
// Get the process group ID of the foreground process group on this terminal
TIOCGPGRP = 0x540f,
// Set the foreground process group ID of this terminal.
TIOCSPGRP = 0x5410,
// Set window size
TIOCGWINSZ = 0x5413,
TIOCSWINSZ = 0x5414
}
#[macro_export]
macro_rules! define_ioctl_cmd {
($($name: ident = $value: expr),*) => {
#[repr(u32)]
@ -40,3 +23,16 @@ macro_rules! define_ioctl_cmd {
}
}
}
define_ioctl_cmd! {
// Get terminal attributes
TCGETS = 0x5401,
TCSETS = 0x5402,
// Get the process group ID of the foreground process group on this terminal
TIOCGPGRP = 0x540f,
// Set the foreground process group ID of this terminal.
TIOCSPGRP = 0x5410,
// Set window size
TIOCGWINSZ = 0x5413,
TIOCSWINSZ = 0x5414
}

View File

@ -1,45 +0,0 @@
//! This definition is from occlum
const KERNEL_NCCS: usize = 19;
type TcflagT = u32;
type CcT = u8;
type SpeedT = u32;
#[derive(Debug, Clone, Copy, Pod)]
#[repr(C)]
pub struct KernelTermios {
pub c_iflags: TcflagT,
pub c_oflags: TcflagT,
pub c_cflags: TcflagT,
pub c_lflags: TcflagT,
pub c_line: CcT,
pub c_cc: [CcT; KERNEL_NCCS],
}
impl KernelTermios {
/// TODO: This fake result is from whitley
pub fn fake_kernel_termios() -> Self {
let mut termios = KernelTermios::new();
termios.c_iflags = 0x6d02;
termios.c_oflags = 0x5;
termios.c_cflags = 0x4bf;
termios.c_lflags = 0x8acb;
termios.c_line = 0;
termios.c_cc = [
0x03, 0x1c, 0x7f, 0x15, 0x04, 0x00, 0x01, 0x00, 0x11, 0x13, 0x1a, 0xff, 0x12, 0x0f,
0x17, 0x16, 0xff, 0x00, 0x00,
];
termios
}
fn new() -> Self {
KernelTermios {
c_iflags: 0,
c_oflags: 0,
c_cflags: 0,
c_lflags: 0,
c_line: 0,
c_cc: [0; KERNEL_NCCS],
}
}
}

View File

@ -1,18 +1,128 @@
use super::events::IoEvents;
use crate::prelude::*;
use crate::tty::{get_console, Tty};
use super::file::{File, FileDescripter};
pub const FD_STDIN: FileDescripter = 0;
pub const FD_STDOUT: FileDescripter = 1;
pub const FD_STDERR: FileDescripter = 2;
#[derive(Debug)]
pub struct Stdin;
pub struct Stdin {
console: Option<Arc<Tty>>,
bind_to_console: bool,
}
#[derive(Debug)]
pub struct Stdout;
pub struct Stdout {
console: Option<Arc<Tty>>,
bind_to_console: bool,
}
#[derive(Debug)]
pub struct Stderr;
pub struct Stderr {
console: Option<Arc<Tty>>,
bind_to_console: bool,
}
impl File for Stdin {}
impl File for Stdout {}
impl File for Stderr {}
impl File for Stdin {
fn poll(&self) -> IoEvents {
if self.bind_to_console {
let console = self.console.as_ref().unwrap();
console.poll()
} else {
todo!()
}
}
fn read(&self, buf: &mut [u8]) -> Result<usize> {
if self.bind_to_console {
let console = self.console.as_ref().unwrap();
console.read(buf)
} else {
todo!()
}
}
fn ioctl(&self, cmd: super::ioctl::IoctlCmd, arg: usize) -> Result<i32> {
if self.bind_to_console {
let console = self.console.as_ref().unwrap();
console.ioctl(cmd, arg)
} else {
todo!()
}
}
}
impl File for Stdout {
fn ioctl(&self, cmd: super::ioctl::IoctlCmd, arg: usize) -> Result<i32> {
if self.bind_to_console {
let console = self.console.as_ref().unwrap();
console.ioctl(cmd, arg)
} else {
todo!()
}
}
fn write(&self, buf: &[u8]) -> Result<usize> {
if self.bind_to_console {
let console = self.console.as_ref().unwrap();
console.write(buf)
} else {
todo!()
}
}
}
impl File for Stderr {
fn ioctl(&self, cmd: super::ioctl::IoctlCmd, arg: usize) -> Result<i32> {
if self.bind_to_console {
let console = self.console.as_ref().unwrap();
console.ioctl(cmd, arg)
} else {
todo!()
}
}
fn write(&self, buf: &[u8]) -> Result<usize> {
if self.bind_to_console {
let console = self.console.as_ref().unwrap();
console.write(buf)
} else {
todo!()
}
}
}
impl Stdin {
/// FIXME: console should be file under devfs.
/// reimplement the function when devfs is enabled.
pub fn new_with_default_console() -> Self {
let console = get_console();
Self {
console: Some(console.clone()),
bind_to_console: true,
}
}
}
impl Stdout {
/// FIXME: console should be file under devfs.
/// reimplement the function when devfs is enabled.
pub fn new_with_default_console() -> Self {
let console = get_console();
Self {
console: Some(console.clone()),
bind_to_console: true,
}
}
}
impl Stderr {
/// FIXME: console should be file under devfs.
/// reimplement the function when devfs is enabled.
pub fn new_with_default_console() -> Self {
let console = get_console();
Self {
console: Some(console.clone()),
bind_to_console: true,
}
}
}

View File

@ -9,6 +9,7 @@
#![feature(exclusive_range_pattern)]
#![feature(btree_drain_filter)]
#![feature(const_option)]
#![feature(extend_one)]
use crate::{prelude::*, user_apps::UserApp};
use kxos_frame::{info, println};
@ -32,6 +33,7 @@ pub mod prelude;
mod process;
pub mod rights;
pub mod syscall;
pub mod tty;
mod user_apps;
mod util;
pub mod vm;
@ -67,6 +69,8 @@ pub fn init_process() {
envp,
} = app;
info!("[kxos-std/lib.rs] spwan {:?} process", app_name);
print!("\n");
print!("BusyBox v1.35.0 built-in shell (ash)\n\n");
Process::spawn_user_process(app_name.clone(), app_content, argv, Vec::new());
}

View File

@ -1,4 +1,4 @@
use core::sync::atomic::{AtomicI32, AtomicUsize, Ordering};
use core::sync::atomic::{AtomicI32, Ordering};
use self::name::ProcessName;
use self::process_group::ProcessGroup;
@ -14,6 +14,7 @@ use self::status::ProcessStatus;
use self::task::create_user_task_from_elf;
use crate::fs::file_table::FileTable;
use crate::prelude::*;
use crate::tty::get_console;
use kxos_frame::sync::WaitQueue;
use kxos_frame::{task::Task, user::UserSpace, vm::VmSpace};
@ -156,6 +157,9 @@ impl Process {
envp: Vec<CString>,
) -> Arc<Self> {
let process = Process::create_user_process(filename, elf_file_content, argv, envp);
// FIXME: How to determine the fg process group?
let pgid = process.pgid();
get_console().set_fg(pgid);
process.send_to_scheduler();
process
}
@ -295,9 +299,10 @@ impl Process {
/// remove current process from old process group.
pub fn set_process_group(&self, process_group: Weak<ProcessGroup>) {
if let Some(old_process_group) = &*self.process_group().lock() {
let old_process_group = old_process_group.upgrade().unwrap();
if let Some(old_process_group) = old_process_group.upgrade() {
old_process_group.remove_process(self.pid());
}
}
let _ = self.process_group.lock().insert(process_group);
}

View File

@ -0,0 +1,17 @@
use super::SyscallReturn;
use super::SYS_CLOSE;
use crate::{fs::file::FileDescripter, prelude::*};
pub fn sys_close(fd: FileDescripter) -> Result<SyscallReturn> {
debug!("[syscall][id={}][SYS_CLOSE]", SYS_CLOSE);
debug!("fd = {}", fd);
let current = current!();
let mut file_table = current.file_table().lock();
match file_table.get_file(fd) {
None => return_errno!(Errno::EBADF),
Some(_) => {
file_table.close_file(fd);
Ok(SyscallReturn::Return(0))
}
}
}

View File

@ -1,3 +1,5 @@
//! constants used in syscall
/// LONGEST ALLOWED FILENAME
pub const MAX_FILENAME_LEN: usize = 128;
pub const MAX_ARGV_NUMBER: usize = 128;

View File

@ -4,6 +4,6 @@ use super::SyscallReturn;
pub fn sys_getuid() -> Result<SyscallReturn> {
debug!("[syscall][id={}][SYS_GETUID]", SYS_GETUID);
// TODO: getuid only return a fake uid now");
// TODO: getuid only return a fake uid now;
Ok(SyscallReturn::Return(0))
}

View File

@ -1,8 +1,5 @@
use crate::fs::file::FileDescripter;
use crate::fs::ioctl::termio::KernelTermios;
use crate::fs::ioctl::IoctlCmd;
use crate::memory::read_val_from_user;
use crate::memory::write_val_to_user;
use crate::prelude::*;
use super::SyscallReturn;
@ -15,40 +12,13 @@ pub fn sys_ioctl(fd: FileDescripter, cmd: u32, arg: Vaddr) -> Result<SyscallRetu
"fd = {}, ioctl_cmd = {:?}, arg = 0x{:x}",
fd, ioctl_cmd, arg
);
match ioctl_cmd {
IoctlCmd::TCGETS => {
if fd == 0 || fd == 1 {
let termio = KernelTermios::fake_kernel_termios();
write_val_to_user(arg, &termio)?;
} else {
todo!()
}
}
IoctlCmd::TIOCGPGRP => {
// FIXME: Get the process group ID of the foreground process group on this terminal.
// We currently only return the pgid of current process
let current = current!();
let pgid = current.pgid();
write_val_to_user(arg, &pgid)?;
}
IoctlCmd::TIOCSPGRP => {
let pgid = read_val_from_user::<i32>(arg)?;
debug!("set foreground process group id: {}", pgid);
// TODO: Set the foreground process group
}
IoctlCmd::TCSETS => {
if fd == 0 || fd == 1 {
let termio = read_val_from_user::<KernelTermios>(arg)?;
debug!("termio = {:x?}", termio);
// TODO: Set termios
} else {
todo!()
let file_table = current.file_table().lock();
match file_table.get_file(fd) {
None => return_errno_with_message!(Errno::EBADF, "Fd does not exist"),
Some(file) => {
let res = file.ioctl(ioctl_cmd, arg)?;
return Ok(SyscallReturn::Return(res as _));
}
}
IoctlCmd::TIOCGWINSZ => {
// TODO:get window size
}
_ => todo!(),
}
Ok(SyscallReturn::Return(0))
}

View File

@ -0,0 +1,11 @@
use crate::{fs::file::FileDescripter, prelude::*};
use super::SyscallReturn;
use super::SYS_LSEEK;
pub fn sys_lseek(fd: FileDescripter, offset: usize, whence: u32) -> Result<SyscallReturn> {
debug!("[syscall][id={}][SYS_LSEEK]", SYS_LSEEK);
debug!("fd = {}, offset = {}, whence = {}", fd, offset, whence);
// TODO: do lseek
Ok(SyscallReturn::Return(0))
}

View File

@ -5,6 +5,7 @@ use crate::syscall::access::sys_access;
use crate::syscall::arch_prctl::sys_arch_prctl;
use crate::syscall::brk::sys_brk;
use crate::syscall::clone::sys_clone;
use crate::syscall::close::sys_close;
use crate::syscall::execve::sys_execve;
use crate::syscall::exit::sys_exit;
use crate::syscall::exit_group::sys_exit_group;
@ -23,12 +24,15 @@ use crate::syscall::gettid::sys_gettid;
use crate::syscall::getuid::sys_getuid;
use crate::syscall::ioctl::sys_ioctl;
use crate::syscall::kill::sys_kill;
use crate::syscall::lseek::sys_lseek;
use crate::syscall::lstat::sys_lstat;
use crate::syscall::mmap::sys_mmap;
use crate::syscall::mprotect::sys_mprotect;
use crate::syscall::munmap::sys_munmap;
use crate::syscall::openat::sys_openat;
use crate::syscall::poll::sys_poll;
use crate::syscall::prctl::sys_prctl;
use crate::syscall::read::sys_read;
use crate::syscall::readlink::sys_readlink;
use crate::syscall::rt_sigaction::sys_rt_sigaction;
use crate::syscall::rt_sigprocmask::sys_rt_sigprocmask;
@ -41,13 +45,13 @@ use crate::syscall::wait4::sys_wait4;
use crate::syscall::waitid::sys_waitid;
use crate::syscall::write::sys_write;
use crate::syscall::writev::sys_writev;
use crate::{define_syscall_nums, syscall_handler};
use kxos_frame::cpu::CpuContext;
mod access;
mod arch_prctl;
mod brk;
mod clone;
mod close;
mod constants;
mod execve;
mod exit;
@ -67,12 +71,15 @@ mod gettid;
mod getuid;
mod ioctl;
mod kill;
mod lseek;
mod lstat;
mod mmap;
mod mprotect;
mod munmap;
mod openat;
mod poll;
mod prctl;
mod read;
mod readlink;
mod rt_sigaction;
mod rt_sigprocmask;
@ -86,13 +93,47 @@ mod waitid;
mod write;
mod writev;
macro_rules! define_syscall_nums {
( $( $name: ident = $num: expr ),+ ) => {
$(
const $name: u64 = $num;
)*
}
}
/// This macro is used to define syscall handler.
/// The first param is ths number of parameters,
/// The second param is the function name of syscall handler,
/// The third is optional, means the args(if parameter number > 0),
/// The third is optional, means if cpu context is required.
macro_rules! syscall_handler {
(0, $fn_name: ident) => { $fn_name() };
(0, $fn_name: ident, $context: expr) => { $fn_name($context) };
(1, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _) };
(1, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $context) };
(2, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _)};
(2, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $context)};
(3, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _)};
(3, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $context)};
(4, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _)};
(4, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _), $context};
(5, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _)};
(5, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _, $context)};
(6, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _, $args[5] as _)};
(6, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _, $args[5] as _, $context)};
}
define_syscall_nums!(
SYS_READ = 0,
SYS_WRITE = 1,
SYS_CLOSE = 3,
SYS_FSTAT = 5,
SYS_LSTAT = 6,
SYS_POLL = 7,
SYS_LSEEK = 8,
SYS_MMAP = 9,
SYS_MPROTECT = 10,
SYS_MUNMAP = 11,
SYS_BRK = 12,
SYS_RT_SIGACTION = 13,
SYS_RT_SIGPROCMASK = 14,
@ -135,6 +176,7 @@ pub struct SyscallArgument {
}
/// Syscall return
#[derive(Debug, Clone, Copy)]
pub enum SyscallReturn {
/// return isize, this value will be used to set rax
Return(isize),
@ -166,11 +208,13 @@ pub fn handle_syscall(context: &mut CpuContext) {
match syscall_return {
Ok(return_value) => {
debug!("syscall return: {:?}", return_value);
if let SyscallReturn::Return(return_value) = return_value {
context.gp_regs.rax = return_value as u64;
}
}
Err(err) => {
debug!("syscall return error: {:?}", err);
let errno = err.error() as i32;
context.gp_regs.rax = (-errno) as u64
}
@ -183,12 +227,16 @@ pub fn syscall_dispatch(
context: &mut CpuContext,
) -> Result<SyscallReturn> {
match syscall_number {
SYS_READ => syscall_handler!(3, sys_read, args),
SYS_WRITE => syscall_handler!(3, sys_write, args),
SYS_CLOSE => syscall_handler!(1, sys_close, args),
SYS_FSTAT => syscall_handler!(2, sys_fstat, args),
SYS_LSTAT => syscall_handler!(2, sys_lstat, args),
SYS_POLL => syscall_handler!(3, sys_poll, args),
SYS_LSEEK => syscall_handler!(3, sys_lseek, args),
SYS_MMAP => syscall_handler!(6, sys_mmap, args),
SYS_MPROTECT => syscall_handler!(3, sys_mprotect, args),
SYS_MUNMAP => syscall_handler!(2, sys_munmap, args),
SYS_BRK => syscall_handler!(1, sys_brk, args),
SYS_RT_SIGACTION => syscall_handler!(4, sys_rt_sigaction, args),
SYS_RT_SIGPROCMASK => syscall_handler!(4, sys_rt_sigprocmask, args),
@ -226,35 +274,3 @@ pub fn syscall_dispatch(
_ => panic!("Unsupported syscall number: {}", syscall_number),
}
}
/// This macro is used to define syscall handler.
/// The first param is ths number of parameters,
/// The second param is the function name of syscall handler,
/// The third is optional, means the args(if parameter number > 0),
/// The third is optional, means if cpu context is required.
#[macro_export]
macro_rules! syscall_handler {
(0, $fn_name: ident) => { $fn_name() };
(0, $fn_name: ident, $context: expr) => { $fn_name($context) };
(1, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _) };
(1, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $context) };
(2, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _)};
(2, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $context)};
(3, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _)};
(3, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $context)};
(4, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _)};
(4, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _), $context};
(5, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _)};
(5, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _, $context)};
(6, $fn_name: ident, $args: ident) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _, $args[5] as _)};
(6, $fn_name: ident, $args: ident, $context: expr) => { $fn_name($args[0] as _, $args[1] as _, $args[2] as _, $args[3] as _, $args[4] as _, $args[5] as _, $context)};
}
#[macro_export]
macro_rules! define_syscall_nums {
( $( $name: ident = $num: expr ),+ ) => {
$(
const $name: u64 = $num;
)*
}
}

View File

@ -0,0 +1,11 @@
use crate::prelude::*;
use super::SyscallReturn;
use super::SYS_MUNMAP;
pub fn sys_munmap(addr: Vaddr, len: usize) -> Result<SyscallReturn> {
debug!("[syscall][id={}][SYS_READ]", SYS_MUNMAP);
debug!("addr = 0x{:x}, len = {}", addr, len);
//TODO: do munmap
Ok(SyscallReturn::Return(0))
}

View File

@ -1,7 +1,9 @@
use crate::fs::file::File;
use crate::fs::file::FileDescripter;
use crate::memory::read_cstring_from_user;
use crate::prelude::*;
use crate::syscall::constants::MAX_FILENAME_LEN;
use crate::tty::get_console;
use super::SyscallReturn;
use super::SYS_OPENAT;
@ -22,8 +24,28 @@ pub fn sys_openat(
);
// TODO: do real openat
// Below are three special files we encountered when running busybox ash.
// We currently only return ENOENT, which means the file does not exist.
if dirfd == AT_FDCWD && pathname == CString::new("/etc/passwd")? {
return_errno!(Errno::ENOENT);
}
if dirfd == AT_FDCWD && pathname == CString::new("/etc/profile")? {
return_errno!(Errno::ENOENT);
}
if dirfd == AT_FDCWD && pathname == CString::new("./trace")? {
return_errno!(Errno::ENOENT);
}
if dirfd == AT_FDCWD && pathname == CString::new("/dev/tty")? {
let tty_file = get_console().clone() as Arc<dyn File>;
let current = current!();
let mut file_table = current.file_table().lock();
let fd = file_table.insert(tty_file);
debug!("openat fd = {}", fd);
return Ok(SyscallReturn::Return(fd as _));
}
todo!()
}

View File

@ -0,0 +1,33 @@
use crate::memory::write_bytes_to_user;
use crate::{fs::file::FileDescripter, prelude::*};
use super::SyscallReturn;
use super::SYS_READ;
pub fn sys_read(fd: FileDescripter, user_buf_addr: Vaddr, buf_len: usize) -> Result<SyscallReturn> {
debug!("[syscall][id={}][SYS_READ]", SYS_READ);
debug!(
"fd = {}, user_buf_ptr = 0x{:x}, buf_len = 0x{:x}",
fd, user_buf_addr, buf_len
);
let current = current!();
let file_table = current.file_table().lock();
let file = file_table.get_file(fd);
match file {
None => return_errno!(Errno::EBADF),
Some(file) => {
let mut read_buf = vec![0u8; buf_len];
let read_len = file.read(&mut read_buf)?;
write_bytes_to_user(user_buf_addr, &read_buf)?;
debug!(
"read_len = {}, read_buf = {:?}",
read_len,
&read_buf[..read_len]
);
// let read_str = core::str::from_utf8(&read_buf[..read_len - 1]).unwrap();
// println!("str = {}" ,read_str);
// todo!();
return Ok(SyscallReturn::Return(read_len as _));
}
}
}

View File

@ -18,8 +18,11 @@ pub fn sys_rt_sigaction(
let sig_action_c = read_val_from_user::<sigaction_t>(sig_action_ptr)?;
let sig_action = SigAction::try_from(sig_action_c).unwrap();
debug!(
"sig_num = {:?}, sig_action = {:x?}, old_sig_action_ptr = 0x{:x}, sigset_size = {}",
sig_num, sig_action, old_sig_action_ptr, sigset_size
"sig_num = {}, sig_action = {:x?}, old_sig_action_ptr = 0x{:x}, sigset_size = {}",
sig_num.sig_name(),
sig_action,
old_sig_action_ptr,
sigset_size
);
let current = current!();

View File

@ -6,7 +6,7 @@ use crate::{
use super::{SyscallReturn, SYS_SETPGID};
pub fn sys_setpgid(pid: Pid, pgid: Pgid) -> Result<SyscallReturn> {
debug!("[syscall][id={}][SYS_PRCTL]", SYS_SETPGID);
debug!("[syscall][id={}][SYS_SETPGID]", SYS_SETPGID);
let current = current!();
// if pid is 0, pid should be the pid of current process
let pid = if pid == 0 { current.pid() } else { pid };

View File

@ -4,6 +4,7 @@ use crate::process::{process_filter::ProcessFilter, wait::wait_child_exit};
use crate::process::wait::WaitOptions;
use super::SyscallReturn;
use super::SYS_WAITID;
pub fn sys_waitid(
which: u64,
@ -13,6 +14,7 @@ pub fn sys_waitid(
rusage_addr: u64,
) -> Result<SyscallReturn> {
// FIXME: what does infoq and rusage use for?
debug!("[syscall][id={}][SYS_WAITID]", SYS_WAITID);
let process_filter = ProcessFilter::from_which_and_id(which, upid);
let wait_options = WaitOptions::from_bits(options as u32).expect("Unknown wait options");
let (exit_code, pid) = wait_child_exit(process_filter, wait_options)?;

View File

@ -1,3 +1,4 @@
use crate::fs::file::FileDescripter;
use crate::prelude::*;
use crate::{memory::read_bytes_from_user, syscall::SYS_WRITE};
@ -7,7 +8,11 @@ use super::SyscallReturn;
const STDOUT: u64 = 1;
const STDERR: u64 = 2;
pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> Result<SyscallReturn> {
pub fn sys_write(
fd: FileDescripter,
user_buf_ptr: Vaddr,
user_buf_len: u64,
) -> Result<SyscallReturn> {
// only suppprt STDOUT now.
debug!("[syscall][id={}][SYS_WRITE]", SYS_WRITE);
debug!(
@ -15,17 +20,16 @@ pub fn sys_write(fd: u64, user_buf_ptr: u64, user_buf_len: u64) -> Result<Syscal
fd, user_buf_ptr, user_buf_len
);
if fd == STDOUT || fd == STDERR {
let current = current!();
let file_table = current.file_table().lock();
match file_table.get_file(fd) {
None => return_errno!(Errno::EBADF),
Some(file) => {
let mut buffer = vec![0u8; user_buf_len as usize];
read_bytes_from_user(user_buf_ptr as usize, &mut buffer)?;
let content = alloc::str::from_utf8(buffer.as_slice())?; // TODO: print content
if fd == STDOUT {
print!("{}", content);
} else {
print!("{}", content);
debug!("write buf = {:?}", buffer);
let write_len = file.write(&buffer)?;
Ok(SyscallReturn::Return(write_len as _))
}
Ok(SyscallReturn::Return(user_buf_len as _))
} else {
panic!("Unsupported fd number {}", fd);
}
}

View File

@ -0,0 +1,85 @@
use crate::{prelude::*, process::Pgid};
use ringbuffer::{ConstGenericRingBuffer, RingBuffer, RingBufferRead, RingBufferWrite};
use super::termio::KernelTermios;
// This implementation refers the implementation of linux
// https://elixir.bootlin.com/linux/latest/source/include/linux/tty_ldisc.h
const BUFFER_CAPACITY: usize = 4096;
#[derive(Debug)]
pub struct LineDiscipline {
/// The write buffer
buffer: ConstGenericRingBuffer<u8, BUFFER_CAPACITY>,
/// The foreground process group
foreground: Option<Pgid>,
/// termios
termios: KernelTermios,
}
impl LineDiscipline {
/// create a new line discipline
pub fn new() -> Self {
Self {
buffer: ConstGenericRingBuffer::new(),
foreground: None,
termios: KernelTermios::default(),
}
}
/// push char to buffer
pub fn push_char(&mut self, mut item: u8) {
if self.termios.is_cooked_mode() {
todo!("We only support raw mode now. Cooked mode will be supported further.");
}
if self.termios.contains_icrnl() {
if item == b'\r' {
item = b'\n'
}
}
self.buffer.push(item);
}
/// read all bytes buffered to dst, return the actual read length.
pub fn read(&mut self, dst: &mut [u8]) -> Result<usize> {
let len = self.buffer.len();
let read_len = len.min(dst.len());
for i in 0..read_len {
if let Some(content) = self.buffer.dequeue() {
dst[i] = content;
} else {
break;
}
}
Ok(read_len)
}
/// write bytes to buffer, if flush to console, then write the content to console
pub fn write(&self, src: &[u8], flush_to_console: bool) -> Result<usize> {
todo!()
}
/// set foreground process group
pub fn set_fg(&mut self, fg_pgid: Pgid) {
self.foreground = Some(fg_pgid);
}
/// get foreground process group id
pub fn get_fg(&self) -> Option<&Pgid> {
self.foreground.as_ref()
}
/// whether there is buffered data
pub fn is_empty(&self) -> bool {
self.buffer.len() == 0
}
pub fn get_termios(&self) -> &KernelTermios {
&self.termios
}
pub fn set_termios(&mut self, termios: KernelTermios) {
self.termios = termios;
}
}

118
src/kxos-std/src/tty/mod.rs Normal file
View File

@ -0,0 +1,118 @@
use kxos_frame::receive_char;
use self::line_discipline::LineDiscipline;
use crate::fs::events::IoEvents;
use crate::fs::ioctl::IoctlCmd;
use crate::memory::{read_val_from_user, write_val_to_user};
use crate::process::Pgid;
use crate::{fs::file::File, prelude::*};
pub mod line_discipline;
pub mod termio;
lazy_static! {
static ref N_TTY: Arc<Tty> = {
let name = CString::new("console").unwrap();
Arc::new(Tty::new(name))
};
}
pub struct Tty {
/// tty_name
name: CString,
/// line discipline
ldisc: Mutex<LineDiscipline>,
}
impl Tty {
pub fn new(name: CString) -> Self {
Tty {
name,
ldisc: Mutex::new(LineDiscipline::new()),
}
}
pub fn set_fg(&self, pgid: Pgid) {
self.ldisc.lock().set_fg(pgid);
}
}
impl File for Tty {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
self.ldisc.lock().read(buf)
}
fn write(&self, buf: &[u8]) -> Result<usize> {
if let Ok(content) = alloc::str::from_utf8(buf) {
print!("{content}");
} else {
println!("Not utf-8 content: {:?}", buf);
}
Ok(buf.len())
}
fn poll(&self) -> IoEvents {
if !self.ldisc.lock().is_empty() {
return IoEvents::POLLIN;
}
loop {
// receive keyboard input
if let Some(byte) = receive_char() {
self.ldisc.lock().push_char(byte);
return IoEvents::POLLIN;
} else {
return IoEvents::empty();
}
}
}
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
match cmd {
IoctlCmd::TCGETS => {
// Get terminal attributes
let ldist_lock = self.ldisc.lock();
let termios = ldist_lock.get_termios();
debug!("get termios = {:?}", termios);
write_val_to_user(arg, termios)?;
Ok(0)
}
IoctlCmd::TIOCGPGRP => {
// FIXME: Get the process group ID of the foreground process group on this terminal.
let ldist_lock = self.ldisc.lock();
let fg_pgid = ldist_lock.get_fg();
match fg_pgid {
None => return_errno_with_message!(Errno::ENOENT, "No fg process group"),
Some(fg_pgid) => {
debug!("fg_pgid = {}", fg_pgid);
write_val_to_user(arg, fg_pgid)?;
Ok(0)
}
}
}
IoctlCmd::TIOCSPGRP => {
// Set the process group id of fg progress group
let pgid = read_val_from_user::<i32>(arg)?;
let mut ldist_lock = self.ldisc.lock();
ldist_lock.set_fg(pgid);
Ok(0)
}
IoctlCmd::TCSETS => {
// Set terminal attributes
let termios = read_val_from_user(arg)?;
debug!("set termios = {:?}", termios);
let mut ldist_lock = self.ldisc.lock();
ldist_lock.set_termios(termios);
Ok(0)
}
IoctlCmd::TIOCGWINSZ => {
// TODO:get window size
Ok(0)
}
_ => todo!(),
}
}
}
pub fn get_console() -> &'static Arc<Tty> {
&N_TTY
}

View File

@ -0,0 +1,158 @@
#![allow(non_camel_case_types)]
use crate::prelude::*;
// This definition is from occlum
const KERNEL_NCCS: usize = 19;
type TcflagT = u32;
type CcT = u8;
type SpeedT = u32;
bitflags! {
#[derive(Pod)]
#[repr(C)]
pub struct C_IFLAGS: u32 {
// https://elixir.bootlin.com/linux/v6.0.9/source/include/uapi/asm-generic/termbits-common.h
const IGNBRK = 0x001; /* Ignore break condition */
const BRKINT = 0x002; /* Signal interrupt on break */
const IGNPAR = 0x004; /* Ignore characters with parity errors */
const PARMRK = 0x008; /* Mark parity and framing errors */
const INPCK = 0x010; /* Enable input parity check */
const ISTRIP = 0x020; /* Strip 8th bit off characters */
const INLCR = 0x040; /* Map NL to CR on input */
const IGNCR = 0x080; /* Ignore CR */
const ICRNL = 0x100; /* Map CR to NL on input */
const IXANY = 0x800; /* Any character will restart after stop */
// https://elixir.bootlin.com/linux/v6.0.9/source/include/uapi/asm-generic/termbits.h
const IUCLC = 0x0200;
const IXON = 0x0400;
const IXOFF = 0x1000;
const IMAXBEL = 0x2000;
const IUTF8 = 0x4000;
}
}
bitflags! {
#[repr(C)]
#[derive(Pod)]
pub struct C_OFLAGS: u32 {
const OPOST = 0x01; /* Perform output processing */
const OCRNL = 0x08;
const ONOCR = 0x10;
const ONLRET= 0x20;
const OFILL = 0x40;
const OFDEL = 0x80;
}
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, Pod)]
pub enum C_CFLAGS {
B0 = 0x00000000, /* hang up */
B50 = 0x00000001,
B75 = 0x00000002,
B110 = 0x00000003,
B134 = 0x00000004,
B150 = 0x00000005,
B200 = 0x00000006,
B300 = 0x00000007,
B600 = 0x00000008,
B1200 = 0x00000009,
B1800 = 0x0000000a,
B2400 = 0x0000000b,
B4800 = 0x0000000c,
B9600 = 0x0000000d,
B19200 = 0x0000000e,
B38400 = 0x0000000f,
}
bitflags! {
#[repr(C)]
#[derive(Pod)]
pub struct C_LFLAGS: u32 {
const ISIG = 0x00001;
const ICANON= 0x00002;
const XCASE = 0x00004;
const ECHO = 0x00008;
const ECHOE = 0x00010;
const ECHOK = 0x00020;
const ECHONL= 0x00040;
const NOFLSH= 0x00080;
const TOSTOP= 0x00100;
const ECHOCTL= 0x00200;
const ECHOPRT= 0x00400;
const ECHOKE= 0x00800;
const FLUSHO= 0x01000;
const PENDIN= 0x04000;
const IEXTEN= 0x08000;
const EXTPROC= 0x10000;
}
}
/* c_cc characters index*/
#[repr(u32)]
#[derive(Debug, Clone, Copy, Pod)]
pub enum CC_C_CHAR {
VINTR = 0,
VQUIT = 1,
VERASE = 2,
VKILL = 3,
VEOF = 4,
VTIME = 5,
VMIN = 6,
VSWTC = 7,
VSTART = 8,
VSTOP = 9,
VSUSP = 10,
VEOL = 11,
VREPRINT = 12,
VDISCARD = 13,
VWERASE = 14,
VLNEXT = 15,
VEOL2 = 16,
}
#[derive(Debug, Clone, Copy, Pod)]
#[repr(C)]
pub struct KernelTermios {
pub c_iflags: C_IFLAGS,
pub c_oflags: C_OFLAGS,
pub c_cflags: C_CFLAGS,
pub c_lflags: C_LFLAGS,
pub c_line: CcT,
pub c_cc: [CcT; KERNEL_NCCS],
}
impl KernelTermios {
pub fn default() -> Self {
Self {
c_iflags: C_IFLAGS::ICRNL,
c_oflags: C_OFLAGS::empty(),
c_cflags: C_CFLAGS::B0,
c_lflags: C_LFLAGS::ICANON | C_LFLAGS::ECHO,
c_line: 0,
c_cc: [0; KERNEL_NCCS],
}
}
fn new() -> Self {
KernelTermios {
c_iflags: C_IFLAGS::empty(),
c_oflags: C_OFLAGS::empty(),
c_cflags: C_CFLAGS::B0,
c_lflags: C_LFLAGS::empty(),
c_line: 0,
c_cc: [0; KERNEL_NCCS],
}
}
pub fn is_cooked_mode(&self) -> bool {
self.c_lflags.contains(C_LFLAGS::ICANON)
}
/// ICRNL means we should map \r to \n
pub fn contains_icrnl(&self) -> bool {
self.c_iflags.contains(C_IFLAGS::ICRNL)
}
}

View File

@ -58,8 +58,19 @@ pub fn get_all_apps() -> Vec<UserApp> {
// busybox
let mut busybox = UserApp::new("/busybox", read_busybox_content());
let argv = ["./busybox", "sh"];
let envp = ["SHELL=/bin/bash", "COLORTERM=truecolor", "TERM_PROGRAM_VERSION=1.73.0", "LC_ADDRESS=zh_CN.UTF-8", "LC_NAME=zh_CN.UTF-8", "LC_MONETARY=zh_CN.UTF-8", "PWD=/", "LOGNAME=jiangjf", "XDG_SESSION_TYPE=tty", "VSCODE_GIT_ASKPASS_NODE=/home/jiangjf/.vscode-server/bin/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/node", "MOTD_SHOWN=pam", "HOME=/home/jiangjf", "LC_PAPER=zh_CN.UTF-8", "LANG=en_US.UTF-8", "LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35", "GIT_ASKPASS=/home/jiangjf/.vscode-server/bin/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/extensions/git/dist/askpass.sh", "SSH_CONNECTION=30.177.3.156 54687 30.77.178.76 22", "VSCODE_GIT_ASKPASS_EXTRA_ARGS=", "LESSCLOSE=/usr/bin/lesspipe %s %s", "XDG_SESSION_CLASS=user", "TERM=xterm-256color", "LC_IDENTIFICATION=zh_CN.UTF-8", "LESSOPEN=| /usr/bin/lesspipe %s", "USER=jiangjf", "VSCODE_GIT_IPC_HANDLE=/run/user/1015/vscode-git-623b69fb06.sock", "SHLVL=2", "LC_TELEPHONE=zh_CN.UTF-8", "LC_MEASUREMENT=zh_CN.UTF-8", "XDG_SESSION_ID=8884", "XDG_RUNTIME_DIR=/run/user/1015", "SSH_CLIENT=30.177.3.156 54687 22", "LC_TIME=zh_CN.UTF-8", "VSCODE_GIT_ASKPASS_MAIN=/home/jiangjf/.vscode-server/bin/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/extensions/git/dist/askpass-main.js", "XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop", "BROWSER=/home/jiangjf/.vscode-server/bin/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/bin/helpers/browser.sh", "PATH=/home/jiangjf/.vscode-server/bin/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/bin/remote-cli:/home/jiangjf/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin", "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1015/bus", "LC_NUMERIC=zh_CN.UTF-8", "TERM_PROGRAM=vscode", "VSCODE_IPC_HOOK_CLI=/run/user/1015/vscode-ipc-ed06ed64-441d-4b59-a8fe-90ce2cf29a8a.sock", "OLDPWD=/"];
// -l option means the busybox is running as logging shell
let argv = ["/busybox", "sh", "-l"];
// let envp = ["SHELL=/bin/bash", "COLORTERM=truecolor", "TERM_PROGRAM_VERSION=1.73.0", "LC_ADDRESS=zh_CN.UTF-8", "LC_NAME=zh_CN.UTF-8", "LC_MONETARY=zh_CN.UTF-8", "PWD=/", "LOGNAME=root", "XDG_SESSION_TYPE=tty", "VSCODE_GIT_ASKPASS_NODE=/home/jiangjf/.vscode-server/bin/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/node", "MOTD_SHOWN=pam", "HOME=/home/jiangjf", "LC_PAPER=zh_CN.UTF-8", "LANG=en_US.UTF-8", "LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35", "GIT_ASKPASS=/home/jiangjf/.vscode-server/bin/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/extensions/git/dist/askpass.sh", "SSH_CONNECTION=30.177.3.156 54687 30.77.178.76 22", "VSCODE_GIT_ASKPASS_EXTRA_ARGS=", "LESSCLOSE=/usr/bin/lesspipe %s %s", "XDG_SESSION_CLASS=user", "TERM=xterm-256color", "LC_IDENTIFICATION=zh_CN.UTF-8", "LESSOPEN=| /usr/bin/lesspipe %s", "USER=jiangjf", "VSCODE_GIT_IPC_HANDLE=/run/user/1015/vscode-git-623b69fb06.sock", "SHLVL=2", "LC_TELEPHONE=zh_CN.UTF-8", "LC_MEASUREMENT=zh_CN.UTF-8", "XDG_SESSION_ID=8884", "XDG_RUNTIME_DIR=/run/user/1015", "SSH_CLIENT=30.177.3.156 54687 22", "LC_TIME=zh_CN.UTF-8", "VSCODE_GIT_ASKPASS_MAIN=/home/jiangjf/.vscode-server/bin/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/extensions/git/dist/askpass-main.js", "XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop", "BROWSER=/home/jiangjf/.vscode-server/bin/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/bin/helpers/browser.sh", "PATH=/home/jiangjf/.vscode-server/bin/8fa188b2b301d36553cbc9ce1b0a146ccb93351f/bin/remote-cli:/home/jiangjf/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin", "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1015/bus", "LC_NUMERIC=zh_CN.UTF-8", "TERM_PROGRAM=vscode", "VSCODE_IPC_HOOK_CLI=/run/user/1015/vscode-ipc-ed06ed64-441d-4b59-a8fe-90ce2cf29a8a.sock", "OLDPWD=/"];
let envp = [
"SHELL=/bin/sh",
"PWD=/",
"LOGNAME=root",
"HOME=/",
"USER=root",
"PATH=",
"OLDPWD=/",
];
let argv = to_vec_cstring(&argv).unwrap();
let envp = to_vec_cstring(&envp).unwrap();
busybox.set_argv(argv);

View File

@ -0,0 +1,6 @@
### How to compile this busybox
We don't include the source code of busybox here since the source code is really large. The busybox can be compiled with following commands.
After download the source code of busybox 1.35.0 and unzip, then cd to the directory of busybox
1. ```make defconfig #set config to default```
2. change the line in .config, `#CONFIG_STATIC is not set` => `CONFIG_STATIC=y`. We need a static-compiled busybox

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c3019f1ee7431b4a7cbcbace4c114679430a6c1277081bed11a290aeb0bc9d6e
size 2644416
oid sha256:be0c152c1e47d3109f808cda876c3a90a1ef959007741e126086552e1063eede
size 2701792