use crate::io;
use super::get_arg;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[cfg(feature = "alloc")]
use super::state::Shell;
#[cfg(feature = "alloc")]
use super::execute::execute_script;
pub fn sh(argc: i32, argv: *const *const u8) -> i32 {
#[cfg(feature = "alloc")]
{
let mut script_file: Option<&[u8]> = None;
let mut command_string: Option<&[u8]> = None;
let mut login_shell = false;
let mut script_args: Vec<&[u8]> = Vec::new();
let shell_name = unsafe { get_arg(argv, 0) }.unwrap_or(b"sh");
let mut i = 1;
while i < argc {
let arg = match unsafe { get_arg(argv, i) } {
Some(a) => a,
None => { i += 1; continue; }
};
if script_file.is_some() {
script_args.push(arg);
i += 1;
continue;
}
if arg == b"-c" {
if i + 1 < argc {
command_string = unsafe { get_arg(argv, i + 1) };
i += 1;
}
i += 1;
if command_string.is_some() {
while i < argc {
if let Some(a) = unsafe { get_arg(argv, i) } {
script_args.push(a);
}
i += 1;
}
}
break;
} else if arg == b"-l" || arg == b"--login" {
login_shell = true;
} else if arg == b"-s" || arg == b"-i" || arg == b"-e"
|| arg == b"-x" || arg == b"-v" || arg == b"-n"
{
} else if !arg.is_empty() && arg[0] == b'-' {
} else {
script_file = Some(arg);
}
i += 1;
}
if let Some(cmd) = command_string {
let mut shell = Shell::new(false);
if login_shell {
source_profile(&mut shell);
}
if !script_args.is_empty() {
let dollar0 = script_args[0];
let params: Vec<&[u8]> = script_args[1..].to_vec();
shell.set_positional_params(dollar0, ¶ms);
} else {
shell.set_positional_params(shell_name, &[]);
}
execute_script(&mut shell, cmd);
return shell.last_status;
}
if let Some(file) = script_file {
let fd = io::open(file, libc::O_RDONLY, 0);
if fd < 0 {
io::write_str(2, b"sh: cannot open ");
io::write_all(2, file);
io::write_str(2, b"\n");
return 127;
}
let content = io::read_all(fd);
io::close(fd);
let mut shell = Shell::new(false);
if login_shell {
source_profile(&mut shell);
}
shell.set_positional_params(file, &script_args);
execute_script(&mut shell, &content);
return shell.last_status;
}
let interactive = io::isatty(0);
let mut shell = Shell::new(interactive);
shell.set_positional_params(shell_name, &[]);
if login_shell || interactive {
source_profile(&mut shell);
}
if interactive {
io::write_str(1, b"ArmyBox sh\n");
}
interactive_loop(&mut shell);
return shell.exit_code;
}
#[cfg(not(feature = "alloc"))]
{
io::write_str(1, b"ArmyBox sh (minimal)\n");
minimal_shell();
0
}
}
pub fn ash(argc: i32, argv: *const *const u8) -> i32 {
sh(argc, argv)
}
pub fn dash(argc: i32, argv: *const *const u8) -> i32 {
sh(argc, argv)
}
#[cfg(feature = "alloc")]
fn source_profile(shell: &mut Shell) {
let profile = b"/etc/profile";
let fd = io::open(profile, libc::O_RDONLY, 0);
if fd >= 0 {
let content = io::read_all(fd);
io::close(fd);
execute_script(shell, &content);
}
}
#[cfg(not(feature = "alloc"))]
pub(super) fn minimal_shell() {
let mut line_buf = [0u8; 1024];
let mut pos = 0;
loop {
if io::isatty(0) {
io::write_str(1, b"$ ");
}
pos = 0;
loop {
let mut c = [0u8; 1];
let n = io::read(0, &mut c);
if n <= 0 {
if pos == 0 { return; }
break;
}
if c[0] == b'\n' { break; }
if pos < line_buf.len() - 1 {
line_buf[pos] = c[0];
pos += 1;
}
}
if pos == 0 { continue; }
let line = &line_buf[..pos];
if line == b"exit" { return; }
if line.starts_with(b"cd ") {
let path = &line[3..];
let mut path_buf = [0u8; 256];
let plen = core::cmp::min(path.len(), path_buf.len() - 1);
path_buf[..plen].copy_from_slice(&path[..plen]);
unsafe {
if libc::chdir(path_buf.as_ptr() as *const i8) != 0 {
io::write_str(2, b"cd: failed\n");
}
}
continue;
}
let pid = io::fork();
if pid == 0 {
let mut args: [*const i8; 32] = [core::ptr::null(); 32];
let mut arg_count = 0;
let mut start = 0;
let mut in_word = false;
for i in 0..=pos {
if i == pos || line_buf[i] == b' ' || line_buf[i] == b'\t' {
if in_word && arg_count < 31 {
line_buf[i] = 0;
args[arg_count] = line_buf[start..].as_ptr() as *const i8;
arg_count += 1;
in_word = false;
}
} else if !in_word {
start = i;
in_word = true;
}
}
if arg_count > 0 {
unsafe { libc::execvp(args[0], args.as_ptr()); }
io::write_str(2, b"sh: command not found\n");
}
io::exit(127);
}
let mut status: i32 = 0;
io::waitpid(pid, &mut status, 0);
}
}
#[cfg(feature = "alloc")]
pub(super) fn interactive_loop(shell: &mut Shell) {
let mut line_buf = Vec::new();
loop {
if shell.should_exit { return; }
if shell.interactive {
io::write_str(1, b"$ ");
}
line_buf.clear();
loop {
let mut c = [0u8; 1];
let n = io::read(0, &mut c);
if n <= 0 {
if line_buf.is_empty() {
shell.should_exit = true;
return;
}
break;
}
if c[0] == b'\n' { break; }
line_buf.push(c[0]);
}
if line_buf.is_empty() { continue; }
execute_script(shell, &line_buf);
}
}