From b224e5d29fcf8642a94ec418018f20e0926695c0 Mon Sep 17 00:00:00 2001 From: Alex Meyer Date: Tue, 22 Apr 2025 19:32:23 -0500 Subject: [PATCH 1/3] Console scaling --- crates/console/src/main.rs | 54 ++++++++++++++++++++++++++----- crates/display-server/src/main.rs | 8 ++--- 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/crates/console/src/main.rs b/crates/console/src/main.rs index cd89350f..0025d877 100644 --- a/crates/console/src/main.rs +++ b/crates/console/src/main.rs @@ -15,10 +15,32 @@ mod vt100; use display_client::proto; use gfx::{color, format}; -use ulib::sys::{pipe, pwrite_all, spawn_elf, FileDesc, SpawnArgs}; +use ulib::sys::{pipe, pwrite_all, spawn_elf, ArgStr, FileDesc, SpawnArgs}; #[no_mangle] -pub extern "C" fn main() { +fn main(argc: usize, argv: *const *const u8) { + let argv_array = unsafe { core::slice::from_raw_parts(argv, argc) }; + let args = argv_array + .iter() + .copied() + .map(|arg| unsafe { core::ffi::CStr::from_ptr(arg) }.to_bytes()) + .map(|arg| core::str::from_utf8(arg).unwrap()) + .collect::>(); + + let remaining_args; + let mut scale = 1; + + if let (Some("--scale"), Some(scale_str)) = (args.get(1).map(|s| *s), args.get(2)) { + if let Ok(s) = scale_str.parse::() { + scale = s; + } + remaining_args = &args[3..]; + } else if args.len() > 0 { + remaining_args = &args[1..]; + } else { + remaining_args = &[]; + } + // Useful font resources: // - https://adafruit.github.io/web-bdftopcf/ // - https://github.com/Tecate/bitmap-fonts @@ -31,10 +53,9 @@ pub extern "C" fn main() { .unwrap(); let mut font_data = alloc::vec![0; size as usize]; let font_data = lz4::decode_into(compressed_font, &mut font_data).unwrap(); - let font = format::pcf::load_pcf(font_data).unwrap(); - let mut buf = display_client::connect(320, 240); + let mut buf = display_client::connect(320 * scale as u16, 240 * scale as u16); let (width, height) = ( buf.video_meta.width as usize, @@ -42,11 +63,9 @@ pub extern "C" fn main() { ); let row_stride = buf.video_meta.row_stride as usize / 4; - println!("Filling screen"); buf.video_mem().fill(color::rgba(0, 0, 0, 255)); let char_dims = font.dimensions(); - let scale = 1; let hpad = 2; let vpad = 0; @@ -69,7 +88,20 @@ pub extern "C" fn main() { let mut editor = editor::LineEditor::new(); let cwd = 3; - let fd = ulib::sys::openat(cwd, b"shell", 0, 0).unwrap(); + let fd; + + if remaining_args.len() > 1 { + fd = ulib::sys::openat(cwd, remaining_args[0].as_bytes(), 0, 0); + } else { + fd = ulib::sys::openat(cwd, b"/shell", 0, 0); + } + let fd = match fd { + Ok(f) => f, + Err(_) => { + println!("Failed to open executable."); + ulib::sys::exit(1); + } + }; let (_shell, shell_stdin_tx, shell_stdout_rx) = { let (shell_stdin_rx, shell_stdin_tx) = pipe(0).unwrap(); @@ -77,7 +109,13 @@ pub extern "C" fn main() { let shell = spawn_elf(&SpawnArgs { fd, - args: &[], + args: &remaining_args + .iter() + .map(|a| ArgStr { + len: a.len(), + ptr: a.as_ptr(), + }) + .collect::>(), stdin: Some(shell_stdin_rx), stdout: Some(shell_stdout_tx), stderr: Some(shell_stdout_tx), diff --git a/crates/display-server/src/main.rs b/crates/display-server/src/main.rs index 9728d74d..675b7a82 100644 --- a/crates/display-server/src/main.rs +++ b/crates/display-server/src/main.rs @@ -84,7 +84,7 @@ fn handle_incoming( } fn init_buffer(width: usize, height: usize) -> BufferInfo { - println!("init_buffer"); + // println!("[disp] init_buffer({}, {})", width, height); let vmem_size = width * height * 4; let header_size = size_of::().next_multiple_of(4096); @@ -93,7 +93,7 @@ fn init_buffer(width: usize, height: usize) -> BufferInfo { let fd = unsafe { ulib::sys::sys_memfd_create() } as u32; let buffer = unsafe { mmap(0, total_size, 0, 0, fd, 0) }.unwrap(); - println!("buffer allocated, {buffer:p}"); + // println!("buffer allocated, {buffer:p}"); let present_sem_fd = ulib::sys::sem_create(0).unwrap(); let present_sem = proto::SemDescriptor(1); @@ -126,10 +126,10 @@ fn init_buffer(width: usize, height: usize) -> BufferInfo { present_sem, }; - println!("Writing header"); + // println!("Writing header"); let ptr = buffer.cast::(); unsafe { ptr.write(header) }; - println!("init done"); + // println!("init done"); BufferInfo { fd, From 42766dac6f1f578052963c35f3482fb0c1f3be5a Mon Sep 17 00:00:00 2001 From: Alex Meyer Date: Tue, 22 Apr 2025 19:32:23 -0500 Subject: [PATCH 2/3] Allow polling process exit status with try_wait --- crates/console/src/main.rs | 7 +++++- crates/kernel/src/event/thread.rs | 8 ++++--- crates/kernel/src/process/mem.rs | 8 ++++--- crates/kernel/src/sync/once_cell.rs | 22 ++++++++++++++++++ crates/kernel/src/syscall/mod.rs | 2 ++ crates/kernel/src/syscall/proc.rs | 35 +++++++++++++++++++++++++---- crates/ulib/src/sys.rs | 11 +++++++++ 7 files changed, 82 insertions(+), 11 deletions(-) diff --git a/crates/console/src/main.rs b/crates/console/src/main.rs index 0025d877..d6188b54 100644 --- a/crates/console/src/main.rs +++ b/crates/console/src/main.rs @@ -103,7 +103,7 @@ fn main(argc: usize, argv: *const *const u8) { } }; - let (_shell, shell_stdin_tx, shell_stdout_rx) = { + let (shell, shell_stdin_tx, shell_stdout_rx) = { let (shell_stdin_rx, shell_stdin_tx) = pipe(0).unwrap(); let (shell_stdout_rx, shell_stdout_tx) = pipe(0).unwrap(); @@ -127,6 +127,11 @@ fn main(argc: usize, argv: *const *const u8) { 'outer: loop { let time_us = unsafe { ulib::sys::sys_get_time_ms() as u64 } * 1000; + if let Some(_) = ulib::sys::try_wait(shell) { + println!("Console child exited, exiting."); + break; + } + while let Some(ev) = buf.server_to_client_queue().try_recv() { match ev.kind { proto::EventKind::INPUT => { diff --git a/crates/kernel/src/event/thread.rs b/crates/kernel/src/event/thread.rs index a0591488..c811a115 100644 --- a/crates/kernel/src/event/thread.rs +++ b/crates/kernel/src/event/thread.rs @@ -223,9 +223,11 @@ impl Thread { pub fn set_exited(&mut self, status: u32) { let exit_code = &self.process.as_ref().unwrap().exit_code; - exit_code.set(crate::process::ExitStatus { - status: status as u32, - }); + exit_code + .try_set(crate::process::ExitStatus { + status: status as u32, + }) + .ok(); } } diff --git a/crates/kernel/src/process/mem.rs b/crates/kernel/src/process/mem.rs index 81d54461..f51fc9a1 100644 --- a/crates/kernel/src/process/mem.rs +++ b/crates/kernel/src/process/mem.rs @@ -353,9 +353,11 @@ pub fn page_fault_handler(ctx: &mut Context, far: usize, _iss: DataAbortISS) -> match vme { None => { let exit_code = &proc.exit_code; - exit_code.set(crate::process::ExitStatus { - status: -1i32 as u32, - }); + exit_code + .try_set(crate::process::ExitStatus { + status: -1i32 as u32, + }) + .ok(); drop(mem); println!("Invalid user access at addr {far:#10x}"); diff --git a/crates/kernel/src/sync/once_cell.rs b/crates/kernel/src/sync/once_cell.rs index c1a60cfc..cefe38bf 100644 --- a/crates/kernel/src/sync/once_cell.rs +++ b/crates/kernel/src/sync/once_cell.rs @@ -31,6 +31,20 @@ impl BlockingOnceCell { self.condvar.notify_all(); } + pub fn try_set(&self, value: T) -> Result<(), T> { + let mut guard = self.ready.lock(); + if *guard { + Err(value) + } else { + unsafe { (*self.data.get()).write(value) }; + *guard = true; + drop(guard); + self.ready_skip.store(true, Ordering::Release); + self.condvar.notify_all(); + Ok(()) + } + } + pub async fn get(&self) -> &T { // TODO: avoid the lock? if self.ready_skip.load(Ordering::Acquire) { @@ -42,6 +56,14 @@ impl BlockingOnceCell { .await; unsafe { (&*self.data.get()).assume_init_ref() } } + + pub fn try_get(&self) -> Option<&T> { + if self.ready_skip.load(Ordering::Acquire) { + return Some(unsafe { (&*self.data.get()).assume_init_ref() }); + } else { + None + } + } } unsafe impl Send for BlockingOnceCell {} diff --git a/crates/kernel/src/syscall/mod.rs b/crates/kernel/src/syscall/mod.rs index b20c4477..0d076cb3 100644 --- a/crates/kernel/src/syscall/mod.rs +++ b/crates/kernel/src/syscall/mod.rs @@ -44,5 +44,7 @@ pub unsafe fn register_syscalls() { register_syscall_handler(28, semaphore::sys_sem_down); register_syscall_handler(30, fb_hack::sys_poll_mouse_event); + + register_syscall_handler(34, proc::sys_try_wait); } } diff --git a/crates/kernel/src/syscall/proc.rs b/crates/kernel/src/syscall/proc.rs index 315fb0c8..116d37c9 100644 --- a/crates/kernel/src/syscall/proc.rs +++ b/crates/kernel/src/syscall/proc.rs @@ -19,7 +19,9 @@ pub unsafe fn sys_shutdown(ctx: &mut Context) -> *mut Context { println!("Not shutting down..."); let thread = context.detach_thread(); let exit_code = &thread.process.as_ref().unwrap().exit_code; - exit_code.set(crate::process::ExitStatus { status: 0 as u32 }); + exit_code + .try_set(crate::process::ExitStatus { status: 0 as u32 }) + .ok(); unsafe { deschedule_thread(DescheduleAction::FreeThread, Some(thread)) } } }) @@ -51,9 +53,11 @@ pub unsafe fn sys_exit(ctx: &mut Context) -> *mut Context { // TODO: split exit into process exit and thread exit? // TODO: ensure processes can't exit without setting this let exit_code = &thread.process.as_ref().unwrap().exit_code; - exit_code.set(crate::process::ExitStatus { - status: status as u32, - }); + exit_code + .try_set(crate::process::ExitStatus { + status: status as u32, + }) + .ok(); unsafe { deschedule_thread(DescheduleAction::FreeThread, Some(thread)) } }) @@ -118,6 +122,29 @@ pub unsafe fn sys_wait(ctx: &mut Context) -> *mut Context { }) } +/// syscall try_wait(fd: u32) -> i64 +pub unsafe fn sys_try_wait(ctx: &mut Context) -> *mut Context { + let fd = ctx.regs[0]; + + run_async_handler(ctx, async move |context: HandlerContext<'_>| { + let proc = context.cur_process().unwrap(); + + let file = proc.file_descriptors.lock().get(fd).cloned(); + let Some(file) = file else { + return context.resume_return(-1i64 as usize); + }; + let Some(file) = file.as_any().downcast_ref::() else { + return context.resume_return(-1i64 as usize); + }; + + if let Some(status) = file.0.try_get() { + context.resume_return(status.status as usize) + } else { + context.resume_return(i64::MIN as usize) + } + }) +} + struct WaitFd(Arc>); impl FileDescriptor for WaitFd { diff --git a/crates/ulib/src/sys.rs b/crates/ulib/src/sys.rs index c1b19725..0fe5baec 100644 --- a/crates/ulib/src/sys.rs +++ b/crates/ulib/src/sys.rs @@ -125,6 +125,8 @@ syscall!(28 => pub fn sys_sem_down(fd: usize) -> isize); syscall!(30 => pub fn sys_poll_mouse_event(buf: *mut u8, buf_len: usize) -> isize); +syscall!(34 => pub fn sys_try_wait(fd: usize) -> isize); + core::arch::global_asm!( ".global {name}; {name}:", "mov x0, lr", //Read link register value into x0 @@ -302,6 +304,15 @@ pub fn wait(fd: FileDesc) -> Result { int_to_error(res) } +pub fn try_wait(fd: FileDesc) -> Option> { + let res = unsafe { sys_try_wait(fd as usize) }; + if res == isize::MIN { + None + } else { + Some(int_to_error(res)) + } +} + pub const MAP_PRIVATE: u32 = 0; pub const MAP_FILE: u32 = 0; //linux mmap ignores this but can have it for readabilty? pub const MAP_FIXED: u32 = 1 << 0; From d7c60e1acb565aff687eb5ea8f664f290bcd3c0f Mon Sep 17 00:00:00 2001 From: Alex Meyer Date: Tue, 22 Apr 2025 19:32:23 -0500 Subject: [PATCH 3/3] Remove old shell utils, refactor shell main loop --- crates/init/ls.rs | 90 -------- crates/init/shell.rs | 167 --------------- crates/shell/src/bin/shell.rs | 393 ++++++++++++++++++---------------- 3 files changed, 203 insertions(+), 447 deletions(-) delete mode 100755 crates/init/ls.rs delete mode 100755 crates/init/shell.rs diff --git a/crates/init/ls.rs b/crates/init/ls.rs deleted file mode 100755 index b9eeb192..00000000 --- a/crates/init/ls.rs +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env bash -#![doc = r##""##] -#![no_std] -#![no_main] - -#[macro_use] -extern crate ulib; - -#[no_mangle] -fn main() { - let root = 3; - println!("Listing dir: {}", root); - - let mut cookie = 0; - let mut data_backing = [0u64; 8192 / 8]; - let data = cast_slice(&mut data_backing); - - fn cast_slice<'a>(s: &'a mut [u64]) -> &'a mut [u8] { - unsafe { - core::slice::from_raw_parts_mut(s.as_mut_ptr().cast::(), s.len() * size_of::()) - } - } - - #[repr(C)] - #[derive(Copy, Clone, Debug)] - pub struct DirEntry { - pub inode: u64, - pub next_entry_cookie: u64, - pub rec_len: u16, - pub name_len: u16, - pub file_type: u8, - pub name: [u8; 3], - // Name is an arbitrary size array; the record is always padded with - // 0 bytes such that rec_len is a multiple of 8 bytes. - } - - loop { - match ulib::sys::pread(root, data, cookie) { - Err(e) => { - println!("Error reading dir: {e}"); - ulib::sys::exit(1); - }, - Ok(0) => break, - Ok(len) => { - let mut i = 0; - while i < len as usize { - let slice = &data[i..]; - assert!(slice.len() >= size_of::()); - let entry = unsafe { *slice.as_ptr().cast::() }; - - let name_off = core::mem::offset_of!(DirEntry, name); - let name = &slice[name_off..][..entry.name_len as usize]; - let name = core::str::from_utf8(name).unwrap(); - println!("{}", name); - i += entry.rec_len as usize; - cookie = entry.next_entry_cookie; - } - if cookie == 0 { - break; - } - } - } - } - - ulib::sys::exit(0); -} diff --git a/crates/init/shell.rs b/crates/init/shell.rs deleted file mode 100755 index 6951d274..00000000 --- a/crates/init/shell.rs +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/env bash -#![doc = r##""##] -#![no_std] -#![no_main] - -#[macro_use] -extern crate ulib; - -use ulib::sys::FileDesc; - -const STDIN_FD: FileDesc = 0; - -fn try_read_stdin(buf: &mut [u8]) -> Result { - ulib::sys::pread(STDIN_FD, buf, 0) -} - -struct LineReader { - buf: [u8; 4096], - cursor: usize, - processed: usize, - cur_base: usize, -} - -impl LineReader { - fn shift(&mut self) { - if self.cur_base != 0 { - self.buf[..self.cursor].copy_within(self.cur_base.., 0); - self.cursor -= self.cur_base; - self.processed -= self.cur_base; - self.cur_base = 0; - } - } -} - -fn readline(reader: &mut LineReader) -> Result<&[u8], usize> { - reader.shift(); - loop { - while reader.processed < reader.cursor { - let i = reader.processed; - reader.processed += 1; - match reader.buf[i] { - b'\r' => { - let base = reader.cur_base; - reader.cur_base = i + 1; - return Ok(&reader.buf[base..i]); - } - b'\x7f' => { - if reader.processed >= 2 { - reader.processed -= 2; - reader.cursor -= 2; - print!("\x08 \x08"); - } else { - reader.processed -= 1; - reader.cursor -= 1; - } - } - c if c.is_ascii_control() => print!("^{}", (c + 64) as char), - c => print!("{}", c as char), - } - } - - let read = try_read_stdin(&mut reader.buf[reader.cursor..])?; - reader.cursor += read; - } -} - -#[no_mangle] -fn main() { - println!("Starting 🐚"); - - let root = 3; - let path = "test.txt"; - let fd = ulib::sys::openat(root, path.as_bytes(), 0, 0).unwrap(); - - println!("File: {}", fd); - - let mut data = [0; 4096]; - - let mut read = 0; - while read < data.len() { - match ulib::sys::pread(fd, &mut data[read..], read as u64) { - Err(_) => break, - Ok(0) => break, - Ok(i) => read += i, - } - } - - println!( - "File content: ======\n{}\n====================", - core::str::from_utf8(&data[..read]).unwrap() - ); - - let stdout = 1; - let buf = b"Stdout write test\n"; - ulib::sys::pwrite_all(stdout, buf, 0).unwrap(); - - let mut reader = LineReader { - buf: [0; 4096], - cursor: 0, - processed: 0, - cur_base: 0, - }; - - loop { - print!("$ "); - let line = match readline(&mut reader) { - Ok(line) => line, - Err(err) => { - println!("Error: {err}"); - break; - } - }; - println!(); - - let line = unsafe { core::str::from_utf8_unchecked(&line) }; - if line.trim().is_empty() { - continue; - } - - if line == "exit" { - break; - } else { - let first = line.split_ascii_whitespace().next().unwrap_or(line); - let root_fd = 3; - if let Ok(file) = ulib::sys::openat(root_fd, first.as_bytes(), 0, 0) { - // TODO: args - let child = ulib::sys::spawn_elf(&ulib::sys::SpawnArgs { - fd: file, - stdin: None, - stdout: None, - }) - .unwrap(); - - let status = ulib::sys::wait(child).unwrap(); - println!("child exited with code {}", status); - } else { - println!("unknown command: {:?}", first); - } - } - } - - ulib::sys::exit(15); -} diff --git a/crates/shell/src/bin/shell.rs b/crates/shell/src/bin/shell.rs index 4f6b3243..506be44f 100644 --- a/crates/shell/src/bin/shell.rs +++ b/crates/shell/src/bin/shell.rs @@ -93,32 +93,47 @@ fn get_file(root_fd: u32, path: &str, flags: usize, mode: usize) -> Result>(); + + if !args.is_empty() { + // run a program first + // This is a hack + let line = args[1..].join(" "); + eval_line(&line, 3); + } - let root = 3; - let path = "test.txt"; - let fd = ulib::sys::openat(root, path.as_bytes(), 0, 0).unwrap(); + println!("Starting shell (🐚)"); - let mut data = [0; 4096]; + // let root = 3; + // let path = "test.txt"; + // let fd = ulib::sys::openat(root, path.as_bytes(), 0, 0).unwrap(); - let mut read = 0; - while read < data.len() { - match ulib::sys::pread(fd, &mut data[read..], read as u64) { - Err(_) => break, - Ok(0) => break, - Ok(i) => read += i, - } - } + // let mut data = [0; 4096]; + + // let mut read = 0; + // while read < data.len() { + // match ulib::sys::pread(fd, &mut data[read..], read as u64) { + // Err(_) => break, + // Ok(0) => break, + // Ok(i) => read += i, + // } + // } - println!( - "File content: ======\n{}\n====================", - core::str::from_utf8(&data[..read]).unwrap() - ); + // println!( + // "File content: ======\n{}\n====================", + // core::str::from_utf8(&data[..read]).unwrap() + // ); - let stdout = 1; - let buf = b"Stdout write test\n"; - ulib::sys::pwrite_all(stdout, buf, 0).unwrap(); + // let stdout = 1; + // let buf = b"Stdout write test\n"; + // ulib::sys::pwrite_all(stdout, buf, 0).unwrap(); let mut reader = LineReader { buf: [0; 4096], @@ -145,199 +160,197 @@ fn main() { continue; } - fn is_pipe(c: u8) -> bool { - c == b'|' + if line == "exit" { + break; + } else { + eval_line(line, root_fd); } + } - fn is_redirection(c: u8) -> bool { - c == b'>' || c == b'<' - } + ulib::sys::exit(0); +} - fn is_background(c: u8) -> bool { - c == b'&' - } +fn is_pipe(c: u8) -> bool { + c == b'|' +} - fn is_special_char(c: u8) -> bool { - is_pipe(c) || is_redirection(c) || is_background(c) +fn is_redirection(c: u8) -> bool { + c == b'>' || c == b'<' +} + +fn is_background(c: u8) -> bool { + c == b'&' +} + +fn is_special_char(c: u8) -> bool { + is_pipe(c) || is_redirection(c) || is_background(c) +} + +fn eval_line(line: &str, root_fd: u32) { + let mut run_background = false; + let split: Vec<&str> = line.split_ascii_whitespace().collect(); + //TODO: Introduce regex for split and grammar for actual parsing + let mut queue = Vec::new(); + + let mut i = 0; + while i < split.len() { + let c = split[i]; + let mut j = i + 1; + while j < split.len() && !is_special_char(split[j].as_bytes()[0]) { + j += 1; } - if line == "exit" { - break; - } else { - let mut run_background = false; - let split: Vec<&str> = line.split_ascii_whitespace().collect(); //TODO: Introduce regex for split and grammar for actual parsing - let mut queue = Vec::new(); - - let mut i = 0; - while i < split.len() { - let c = split[i]; - let mut j = i + 1; - while j < split.len() && !is_special_char(split[j].as_bytes()[0]) { - j += 1; - } + let mut redirects = Vec::new(); + let mut k = j; + while k < split.len() && is_redirection(split[k].as_bytes()[0]) { + let redirection_str = split[k]; + let redirection_type; + if redirection_str == "<" { + redirection_type = 0; + } else if redirection_str == "<<" { + redirection_type = 1; + } else if redirection_str == ">" { + redirection_type = 2; + } else if redirection_str == ">>" { + redirection_type = 3; + } else { + redirection_type = -1; + } - let mut redirects = Vec::new(); - let mut k = j; - while k < split.len() && is_redirection(split[k].as_bytes()[0]) { - let redirection_str = split[k]; - let redirection_type; - if redirection_str == "<" { - redirection_type = 0; - } else if redirection_str == "<<" { - redirection_type = 1; - } else if redirection_str == ">" { - redirection_type = 2; - } else if redirection_str == ">>" { - redirection_type = 3; - } else { - redirection_type = -1; - } + k += 1; + redirects.push(Redirection { + redirect_type: redirection_type, + file: split[k], + }); + k += 1; + } - k += 1; - redirects.push(Redirection { - redirect_type: redirection_type, - file: split[k], - }); - k += 1; - } + if k < split.len() && is_background(split[k].as_bytes()[0]) { + run_background = true; + k += 1; + } - if k < split.len() && is_background(split[k].as_bytes()[0]) { - run_background = true; - k += 1; - } + // println!("Command: {}, Args: {:?}, i {} j {}", c, &split[(i + 1)..j], i, j); + queue.push(SimpleCommand { + command: c, + args: split[i..j].to_vec(), + redirections: redirects, + }); + i = k; - // println!("Command: {}, Args: {:?}, i {} j {}", c, &split[(i + 1)..j], i, j); - queue.push(SimpleCommand { - command: c, - args: split[i..j].to_vec(), - redirections: redirects, - }); - i = k; + if i < split.len() && split[i].as_bytes()[0] == b'|' { + i += 1; + } + } - if i < split.len() && split[i].as_bytes()[0] == b'|' { - i += 1; + let mut next_pipe = None; + for i in 0..queue.len() { + let next = queue.get(i).unwrap(); + let has_next = i < queue.len() - 1; + + let command = next.command; + let args = &next.args; + if command == "cd" { + match ulib::sys::openat(root_fd, args[1].as_bytes(), 0, 0) { + Ok(file) => { + let err = ulib::sys::dup3(file, root_fd, 0); + if err.is_err() { + println!("cd: failed to change directory: {}", args[1]); + } + } + Err(err1) => { + if (err1 as i32) == -1 { + println!("cd: no such file or directory: {}", args[1]); + } else if (err1 as i32) == -2 { + println!("cd: not a directory: {}", args[1]); + } else { + println!("cd: unknown error: {}", err1); + } } } + } else if let Ok(file) = get_file(root_fd, command, 0, 0) { + use ulib::sys::ArgStr; + + let argstrs: Vec = args + .iter() + .map(|s| ArgStr { + len: s.len(), + ptr: s.as_ptr(), + }) + .collect(); + + let mut cur_stdout; + let mut future_next_pipe = None; + + if has_next { + let (read_fd, write_fd) = ulib::sys::pipe(0).unwrap(); + cur_stdout = Some(write_fd); + future_next_pipe = Some(read_fd); + } else { + cur_stdout = None; + } - let mut next_pipe = None; - for i in 0..queue.len() { - let next = queue.get(i).unwrap(); - let has_next = i < queue.len() - 1; - - let command = next.command; - let args = &next.args; - if command == "cd" { - match ulib::sys::openat(root_fd, args[1].as_bytes(), 0, 0) { - Ok(file) => { - let err = ulib::sys::dup3(file, root_fd, 0); - if err.is_err() { - println!("cd: failed to change directory: {}", args[1]); + if next.redirections.len() > 0 { + for redirect in &next.redirections { + match redirect.redirect_type { + 0 => { + //< + if let Ok(redirect_file) = + ulib::sys::openat(root_fd, redirect.file.as_bytes(), 0, 0) + { + next_pipe = Some(redirect_file); + } else { + println!("failed to open file for redirection: {}", redirect.file); } } - Err(err1) => { - if (err1 as i32) == -1 { - println!("cd: no such file or directory: {}", args[1]); - } else if (err1 as i32) == -2 { - println!("cd: not a directory: {}", args[1]); + 1 => { + //<< + println!("<< redirection not implemented"); + continue; + } + 2 => { + //> + if let Ok(redirect_file) = + ulib::sys::openat(root_fd, redirect.file.as_bytes(), 0, 0) + { + cur_stdout = Some(redirect_file); } else { - println!("cd: unknown error: {}", err1); + println!("failed to open file for redirection: {}", redirect.file); } } - } - } else if let Ok(file) = get_file(root_fd, command, 0, 0) { - use ulib::sys::ArgStr; - - let argstrs: Vec = args - .iter() - .map(|s| ArgStr { - len: s.len(), - ptr: s.as_ptr(), - }) - .collect(); - - let mut cur_stdout; - let mut future_next_pipe = None; - - if has_next { - let (read_fd, write_fd) = ulib::sys::pipe(0).unwrap(); - cur_stdout = Some(write_fd); - future_next_pipe = Some(read_fd); - } else { - cur_stdout = None; - } - - if next.redirections.len() > 0 { - for redirect in &next.redirections { - match redirect.redirect_type { - 0 => { - //< - if let Ok(redirect_file) = - ulib::sys::openat(root_fd, redirect.file.as_bytes(), 0, 0) - { - next_pipe = Some(redirect_file); - } else { - println!( - "failed to open file for redirection: {}", - redirect.file - ); - } - } - 1 => { - //<< - println!("<< redirection not implemented"); - continue; - } - 2 => { - //> - if let Ok(redirect_file) = - ulib::sys::openat(root_fd, redirect.file.as_bytes(), 0, 0) - { - cur_stdout = Some(redirect_file); - } else { - println!( - "failed to open file for redirection: {}", - redirect.file - ); - } - } - 3 => { - //<< - println!("<< redirection not implemented"); - continue; - } - _ => { - println!( - "unknown redirection type: {}", - redirect.redirect_type - ); - continue; - } - } + 3 => { + //<< + println!("<< redirection not implemented"); + continue; + } + _ => { + println!("unknown redirection type: {}", redirect.redirect_type); + continue; } } + } + } - let child = ulib::sys::spawn_elf(&ulib::sys::SpawnArgs { - fd: file, - stdin: next_pipe, - stdout: cur_stdout, - stderr: None, - args: &argstrs, - }) - .unwrap(); - - next_pipe = future_next_pipe; - - if !run_background { - //TODO: Hacky solution -> need tracking - let status = ulib::sys::wait(child).unwrap(); - println!("child exited with code {}", status); - } - } else { - println!("unknown command: {:?}", command); + let child = ulib::sys::spawn_elf(&ulib::sys::SpawnArgs { + fd: file, + stdin: next_pipe, + stdout: cur_stdout, + stderr: None, + args: &argstrs, + }) + .unwrap(); + + next_pipe = future_next_pipe; + + if !run_background { + //TODO: Hacky solution -> need tracking + let status = ulib::sys::wait(child).unwrap(); + if status != 0 { + println!("child exited with code {}", status); } } + } else { + println!("unknown command: {:?}", command); } } - - ulib::sys::exit(15); }