feature: shell exec
This commit is contained in:
parent
87c13d3920
commit
6eac5287a2
1
Makefile
1
Makefile
@ -95,6 +95,7 @@ initrd:
|
||||
mkdir -p $(O)/rootfs/bin
|
||||
cp target/$(ARCH)-osdev5/$(PROFILE)/init $(O)/rootfs/init
|
||||
cp target/$(ARCH)-osdev5/$(PROFILE)/shell $(O)/rootfs/bin
|
||||
cp target/$(ARCH)-osdev5/$(PROFILE)/fuzzy $(O)/rootfs/bin
|
||||
cd $(O)/rootfs && tar cf ../initrd.img `find -type f -printf "%P\n"`
|
||||
ifeq ($(MACH),orangepi3)
|
||||
$(MKIMAGE) \
|
||||
|
@ -29,7 +29,7 @@ pub use block::{BlockAllocator, BlockRef};
|
||||
mod bvec;
|
||||
use bvec::Bvec;
|
||||
mod tar;
|
||||
use tar::TarIterator;
|
||||
use tar::{TarIterator, Tar};
|
||||
mod file;
|
||||
use file::FileInode;
|
||||
mod dir;
|
||||
@ -67,8 +67,10 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn create_node_initial(self: Rc<Self>, name: &str, kind: VnodeKind) -> VnodeRef {
|
||||
fn create_node_initial(self: Rc<Self>, name: &str, tar: &Tar) -> VnodeRef {
|
||||
let kind = tar.node_kind();
|
||||
let node = Vnode::new(name, kind, Vnode::SEEKABLE);
|
||||
node.props_mut().mode = tar.mode();
|
||||
node.set_fs(self.clone());
|
||||
match kind {
|
||||
VnodeKind::Directory => node.set_data(Box::new(DirInode::new(self.alloc))),
|
||||
@ -111,7 +113,10 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
|
||||
}
|
||||
|
||||
unsafe fn load_tar(self: Rc<Self>, base: *const u8, size: usize) -> Result<VnodeRef, Errno> {
|
||||
let root = self.clone().create_node_initial("", VnodeKind::Directory);
|
||||
let root = Vnode::new("", VnodeKind::Directory, Vnode::SEEKABLE);
|
||||
root.set_fs(self.clone());
|
||||
root.set_data(Box::new(DirInode::new(self.alloc)));
|
||||
root.props_mut().mode = FileMode::default_dir();
|
||||
|
||||
// 1. Create all the paths in TAR
|
||||
for block in TarIterator::new(base, base.add(size)) {
|
||||
@ -120,7 +125,7 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
|
||||
let parent = self.clone().make_path(root.clone(), dirname, true)?;
|
||||
let node = self
|
||||
.clone()
|
||||
.create_node_initial(basename, block.node_kind());
|
||||
.create_node_initial(basename, block);
|
||||
assert_eq!(node.kind(), block.node_kind());
|
||||
parent.attach(node);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use libsys::error::Errno;
|
||||
use libsys::{error::Errno, stat::FileMode};
|
||||
use vfs::VnodeKind;
|
||||
|
||||
#[repr(packed)]
|
||||
@ -81,6 +81,10 @@ impl Tar {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mode(&self) -> FileMode {
|
||||
FileMode::from_bits(from_octal(&self.mode) as u32).unwrap()
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &[u8] {
|
||||
unsafe {
|
||||
core::slice::from_raw_parts(
|
||||
|
@ -1,11 +1,11 @@
|
||||
use crate::{File, FileRef, Filesystem};
|
||||
use crate::{Ioctx, File, FileRef, Filesystem};
|
||||
use alloc::{borrow::ToOwned, boxed::Box, rc::Rc, string::String, vec::Vec};
|
||||
use core::cell::{RefCell, RefMut};
|
||||
use core::fmt;
|
||||
use libsys::{
|
||||
error::Errno,
|
||||
ioctl::IoctlCmd,
|
||||
stat::{FileMode, OpenFlags, Stat},
|
||||
stat::{AccessMode, FileMode, OpenFlags, Stat},
|
||||
};
|
||||
|
||||
/// Convenience type alias for [Rc<Vnode>]
|
||||
@ -31,7 +31,7 @@ pub(crate) struct TreeNode {
|
||||
|
||||
/// File property cache struct
|
||||
pub struct VnodeProps {
|
||||
mode: FileMode,
|
||||
pub mode: FileMode,
|
||||
}
|
||||
|
||||
/// Virtual filesystem node struct, generalizes access to
|
||||
@ -122,6 +122,11 @@ impl Vnode {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// Returns a borrowed reference to cached file properties
|
||||
pub fn props_mut(&self) -> RefMut<VnodeProps> {
|
||||
self.props.borrow_mut()
|
||||
}
|
||||
|
||||
/// Sets an associated [VnodeImpl] for the [Vnode]
|
||||
pub fn set_data(&self, data: Box<dyn VnodeImpl>) {
|
||||
*self.data.borrow_mut() = Some(data);
|
||||
@ -408,6 +413,38 @@ impl Vnode {
|
||||
Err(Errno::NotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_access(&self, ioctx: &Ioctx, access: AccessMode) -> Result<(), Errno> {
|
||||
let props = self.props.borrow();
|
||||
let mode = props.mode;
|
||||
|
||||
if access.contains(AccessMode::F_OK) {
|
||||
if access.intersects(AccessMode::R_OK | AccessMode::W_OK | AccessMode::X_OK) {
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
return Ok(());
|
||||
} else {
|
||||
if access.contains(AccessMode::F_OK) {
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
|
||||
// Check user
|
||||
if access.contains(AccessMode::R_OK) && !mode.contains(FileMode::USER_READ) {
|
||||
return Err(Errno::PermissionDenied);
|
||||
}
|
||||
if access.contains(AccessMode::W_OK) && !mode.contains(FileMode::USER_WRITE) {
|
||||
return Err(Errno::PermissionDenied);
|
||||
}
|
||||
if access.contains(AccessMode::X_OK) && !mode.contains(FileMode::USER_EXEC) {
|
||||
return Err(Errno::PermissionDenied);
|
||||
}
|
||||
|
||||
// TODO check group
|
||||
// TODO check other
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Vnode {
|
||||
|
@ -243,7 +243,9 @@ impl Process {
|
||||
|
||||
if lock.threads.len() == 1 {
|
||||
// TODO call Process::exit instead?
|
||||
todo!();
|
||||
drop(lock);
|
||||
Process::exit(ExitCode::from(0));
|
||||
panic!();
|
||||
}
|
||||
|
||||
lock.threads.retain(|&e| e != tid);
|
||||
|
@ -283,7 +283,7 @@ impl Thread {
|
||||
}
|
||||
|
||||
/// Switches process main thread to a signal handler
|
||||
pub fn enter_signal(&self, signal: Signal, ttbr0: usize) {
|
||||
pub fn enter_signal(self: ThreadRef, signal: Signal, ttbr0: usize) {
|
||||
if self
|
||||
.signal_pending
|
||||
.compare_exchange_weak(0, signal as u32, Ordering::SeqCst, Ordering::Relaxed)
|
||||
@ -294,7 +294,9 @@ impl Thread {
|
||||
|
||||
let mut lock = self.inner.lock();
|
||||
if lock.signal_entry == 0 || lock.signal_stack == 0 {
|
||||
todo!();
|
||||
drop(lock);
|
||||
Process::exit_thread(self);
|
||||
panic!();
|
||||
}
|
||||
|
||||
let signal_ctx = unsafe { &mut *self.signal_ctx.get() };
|
||||
|
@ -12,7 +12,7 @@ use libsys::{
|
||||
ioctl::IoctlCmd,
|
||||
proc::Pid,
|
||||
signal::{Signal, SignalDestination},
|
||||
stat::{FdSet, FileDescriptor, FileMode, OpenFlags, Stat, AT_EMPTY_PATH},
|
||||
stat::{FdSet, AccessMode, FileDescriptor, FileMode, OpenFlags, Stat, AT_EMPTY_PATH},
|
||||
traits::{Read, Write},
|
||||
};
|
||||
use vfs::VnodeRef;
|
||||
@ -233,6 +233,18 @@ pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
|
||||
|
||||
wait::select(Thread::current(), rfds, wfds, timeout)
|
||||
}
|
||||
abi::SYS_FACCESSAT => {
|
||||
let at_fd = FileDescriptor::from_i32(args[0] as i32)?;
|
||||
let path = validate_user_str(args[1], args[2])?;
|
||||
let mode = AccessMode::from_bits(args[3] as u32).ok_or(Errno::InvalidArgument)?;
|
||||
let flags = args[4] as u32;
|
||||
|
||||
let proc = Process::current();
|
||||
let mut io = proc.io.lock();
|
||||
|
||||
find_at_node(&mut io, at_fd, path, flags & AT_EMPTY_PATH != 0)?.check_access(io.ioctx(), mode)?;
|
||||
Ok(0)
|
||||
},
|
||||
|
||||
_ => {
|
||||
let thread = Thread::current();
|
||||
|
@ -20,3 +20,4 @@ pub const SYS_EXECVE: usize = 8;
|
||||
pub const SYS_WAITPID: usize = 9;
|
||||
pub const SYS_IOCTL: usize = 10;
|
||||
pub const SYS_SELECT: usize = 11;
|
||||
pub const SYS_FACCESSAT: usize = 12;
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
ioctl::IoctlCmd,
|
||||
proc::{ExitCode, Pid},
|
||||
signal::{Signal, SignalDestination},
|
||||
stat::{FdSet, FileDescriptor, FileMode, OpenFlags, Stat},
|
||||
stat::{AccessMode, FdSet, FileDescriptor, FileMode, OpenFlags, Stat},
|
||||
};
|
||||
|
||||
// TODO document the syscall ABI
|
||||
@ -325,3 +325,22 @@ pub fn sys_select(
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn sys_faccessat(
|
||||
fd: Option<FileDescriptor>,
|
||||
name: &str,
|
||||
mode: AccessMode,
|
||||
flags: u32,
|
||||
) -> Result<(), Errno> {
|
||||
Errno::from_syscall_unit(unsafe {
|
||||
syscall!(
|
||||
abi::SYS_FACCESSAT,
|
||||
argn!(FileDescriptor::into_i32(fd)),
|
||||
argp!(name.as_ptr()),
|
||||
argn!(name.len()),
|
||||
argn!(mode.bits()),
|
||||
argn!(flags)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ pub enum Errno {
|
||||
NotADirectory,
|
||||
NotImplemented,
|
||||
OutOfMemory,
|
||||
PermissionDenied,
|
||||
ReadOnly,
|
||||
TimedOut,
|
||||
TooManyDescriptors,
|
||||
|
@ -31,6 +31,15 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct AccessMode: u32 {
|
||||
const R_OK = 1 << 0;
|
||||
const W_OK = 1 << 1;
|
||||
const X_OK = 1 << 2;
|
||||
const F_OK = 1 << 3;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct FdSet {
|
||||
bits: [u64; 2]
|
||||
|
@ -2,7 +2,8 @@ pub use libsys::signal::{Signal, SignalDestination};
|
||||
pub use libsys::proc::ExitCode;
|
||||
pub use libsys::termios;
|
||||
pub use libsys::calls::*;
|
||||
pub use libsys::stat::{self, FileDescriptor};
|
||||
pub use libsys::stat::{self, AccessMode, FileDescriptor};
|
||||
pub use libsys::error::Errno;
|
||||
|
||||
use core::sync::atomic::{Ordering, AtomicBool};
|
||||
|
||||
|
@ -13,6 +13,10 @@ path = "src/init/main.rs"
|
||||
name = "shell"
|
||||
path = "src/shell/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "fuzzy"
|
||||
path = "src/fuzzy/main.rs"
|
||||
|
||||
[dependencies]
|
||||
libusr = { path = "../libusr" }
|
||||
lazy_static = { version = "*", features = ["spin_no_std"] }
|
||||
|
10
user/src/fuzzy/main.rs
Normal file
10
user/src/fuzzy/main.rs
Normal file
@ -0,0 +1,10 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate libusr;
|
||||
|
||||
#[no_mangle]
|
||||
fn main() -> i32 {
|
||||
0
|
||||
}
|
@ -3,34 +3,56 @@
|
||||
|
||||
#[macro_use]
|
||||
extern crate libusr;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate alloc;
|
||||
|
||||
use libusr::thread;
|
||||
use alloc::borrow::ToOwned;
|
||||
use libusr::sys::{sys_faccessat, sys_exit, sys_execve, sys_waitpid, sys_fork, ExitCode, Errno, AccessMode};
|
||||
use libusr::io::{self, Read};
|
||||
use libusr::sys::{Signal, SignalDestination};
|
||||
use libusr::sync::Mutex;
|
||||
|
||||
fn sleep(ns: u64) {
|
||||
let mut rem = [0; 2];
|
||||
libusr::sys::sys_ex_nanosleep(ns, &mut rem).unwrap();
|
||||
fn readline<'a, F: Read>(f: &mut F, bytes: &'a mut [u8]) -> Result<Option<&'a str>, io::Error> {
|
||||
let size = f.read(bytes)?;
|
||||
Ok(if size == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(core::str::from_utf8(&bytes[..size]).unwrap().trim_end_matches('\n'))
|
||||
})
|
||||
}
|
||||
|
||||
fn execvp(cmd: &str) -> ! {
|
||||
sys_execve(&("/bin/".to_owned() + cmd));
|
||||
sys_exit(ExitCode::from(-1));
|
||||
}
|
||||
|
||||
fn execute(line: &str) -> Result<ExitCode, Errno> {
|
||||
let mut words = line.split(' ');
|
||||
let cmd = words.next().unwrap();
|
||||
|
||||
if let Some(pid) = sys_fork()? {
|
||||
let mut status = 0;
|
||||
sys_waitpid(pid, &mut status)?;
|
||||
Ok(ExitCode::from(status))
|
||||
} else {
|
||||
execvp(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
fn main() -> i32 {
|
||||
let value = 1234;
|
||||
let thread = thread::spawn(move || {
|
||||
trace!("Closure is alive: {}", value);
|
||||
sleep(2_000_000_000);
|
||||
trace!("Closure will now exit");
|
||||
let mut buf = [0; 256];
|
||||
let mut stdin = io::stdin();
|
||||
|
||||
value - 100
|
||||
});
|
||||
sleep(1_000_000_000);
|
||||
|
||||
trace!("???");
|
||||
|
||||
trace!("Thread joined: {:?}", thread.join());
|
||||
loop {
|
||||
print!("> ");
|
||||
let line = readline(&mut stdin, &mut buf).unwrap();
|
||||
if line.is_none() {
|
||||
break;
|
||||
}
|
||||
let line = line.unwrap().trim_start_matches(' ');
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
execute(line);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user