feature: shell exec

This commit is contained in:
Mark Poliakov 2021-11-20 13:54:06 +02:00
parent 87c13d3920
commit 6eac5287a2
15 changed files with 164 additions and 34 deletions

View File

@ -95,6 +95,7 @@ initrd:
mkdir -p $(O)/rootfs/bin mkdir -p $(O)/rootfs/bin
cp target/$(ARCH)-osdev5/$(PROFILE)/init $(O)/rootfs/init cp target/$(ARCH)-osdev5/$(PROFILE)/init $(O)/rootfs/init
cp target/$(ARCH)-osdev5/$(PROFILE)/shell $(O)/rootfs/bin 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"` cd $(O)/rootfs && tar cf ../initrd.img `find -type f -printf "%P\n"`
ifeq ($(MACH),orangepi3) ifeq ($(MACH),orangepi3)
$(MKIMAGE) \ $(MKIMAGE) \

View File

@ -29,7 +29,7 @@ pub use block::{BlockAllocator, BlockRef};
mod bvec; mod bvec;
use bvec::Bvec; use bvec::Bvec;
mod tar; mod tar;
use tar::TarIterator; use tar::{TarIterator, Tar};
mod file; mod file;
use file::FileInode; use file::FileInode;
mod dir; mod dir;
@ -67,8 +67,10 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
Ok(res) 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); let node = Vnode::new(name, kind, Vnode::SEEKABLE);
node.props_mut().mode = tar.mode();
node.set_fs(self.clone()); node.set_fs(self.clone());
match kind { match kind {
VnodeKind::Directory => node.set_data(Box::new(DirInode::new(self.alloc))), 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> { 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 // 1. Create all the paths in TAR
for block in TarIterator::new(base, base.add(size)) { 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 parent = self.clone().make_path(root.clone(), dirname, true)?;
let node = self let node = self
.clone() .clone()
.create_node_initial(basename, block.node_kind()); .create_node_initial(basename, block);
assert_eq!(node.kind(), block.node_kind()); assert_eq!(node.kind(), block.node_kind());
parent.attach(node); parent.attach(node);
} }

View File

@ -1,4 +1,4 @@
use libsys::error::Errno; use libsys::{error::Errno, stat::FileMode};
use vfs::VnodeKind; use vfs::VnodeKind;
#[repr(packed)] #[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] { pub fn data(&self) -> &[u8] {
unsafe { unsafe {
core::slice::from_raw_parts( core::slice::from_raw_parts(

View File

@ -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 alloc::{borrow::ToOwned, boxed::Box, rc::Rc, string::String, vec::Vec};
use core::cell::{RefCell, RefMut}; use core::cell::{RefCell, RefMut};
use core::fmt; use core::fmt;
use libsys::{ use libsys::{
error::Errno, error::Errno,
ioctl::IoctlCmd, ioctl::IoctlCmd,
stat::{FileMode, OpenFlags, Stat}, stat::{AccessMode, FileMode, OpenFlags, Stat},
}; };
/// Convenience type alias for [Rc<Vnode>] /// Convenience type alias for [Rc<Vnode>]
@ -31,7 +31,7 @@ pub(crate) struct TreeNode {
/// File property cache struct /// File property cache struct
pub struct VnodeProps { pub struct VnodeProps {
mode: FileMode, pub mode: FileMode,
} }
/// Virtual filesystem node struct, generalizes access to /// Virtual filesystem node struct, generalizes access to
@ -122,6 +122,11 @@ impl Vnode {
&self.name &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] /// Sets an associated [VnodeImpl] for the [Vnode]
pub fn set_data(&self, data: Box<dyn VnodeImpl>) { pub fn set_data(&self, data: Box<dyn VnodeImpl>) {
*self.data.borrow_mut() = Some(data); *self.data.borrow_mut() = Some(data);
@ -408,6 +413,38 @@ impl Vnode {
Err(Errno::NotImplemented) 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 { impl fmt::Debug for Vnode {

View File

@ -243,7 +243,9 @@ impl Process {
if lock.threads.len() == 1 { if lock.threads.len() == 1 {
// TODO call Process::exit instead? // TODO call Process::exit instead?
todo!(); drop(lock);
Process::exit(ExitCode::from(0));
panic!();
} }
lock.threads.retain(|&e| e != tid); lock.threads.retain(|&e| e != tid);

View File

@ -283,7 +283,7 @@ impl Thread {
} }
/// Switches process main thread to a signal handler /// 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 if self
.signal_pending .signal_pending
.compare_exchange_weak(0, signal as u32, Ordering::SeqCst, Ordering::Relaxed) .compare_exchange_weak(0, signal as u32, Ordering::SeqCst, Ordering::Relaxed)
@ -294,7 +294,9 @@ impl Thread {
let mut lock = self.inner.lock(); let mut lock = self.inner.lock();
if lock.signal_entry == 0 || lock.signal_stack == 0 { 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() }; let signal_ctx = unsafe { &mut *self.signal_ctx.get() };

View File

@ -12,7 +12,7 @@ use libsys::{
ioctl::IoctlCmd, ioctl::IoctlCmd,
proc::Pid, proc::Pid,
signal::{Signal, SignalDestination}, 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}, traits::{Read, Write},
}; };
use vfs::VnodeRef; use vfs::VnodeRef;
@ -233,6 +233,18 @@ pub fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
wait::select(Thread::current(), rfds, wfds, timeout) 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(); let thread = Thread::current();

View File

@ -20,3 +20,4 @@ pub const SYS_EXECVE: usize = 8;
pub const SYS_WAITPID: usize = 9; pub const SYS_WAITPID: usize = 9;
pub const SYS_IOCTL: usize = 10; pub const SYS_IOCTL: usize = 10;
pub const SYS_SELECT: usize = 11; pub const SYS_SELECT: usize = 11;
pub const SYS_FACCESSAT: usize = 12;

View File

@ -4,7 +4,7 @@ use crate::{
ioctl::IoctlCmd, ioctl::IoctlCmd,
proc::{ExitCode, Pid}, proc::{ExitCode, Pid},
signal::{Signal, SignalDestination}, signal::{Signal, SignalDestination},
stat::{FdSet, FileDescriptor, FileMode, OpenFlags, Stat}, stat::{AccessMode, FdSet, FileDescriptor, FileMode, OpenFlags, Stat},
}; };
// TODO document the syscall ABI // 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)
)
})
}

View File

@ -15,6 +15,7 @@ pub enum Errno {
NotADirectory, NotADirectory,
NotImplemented, NotImplemented,
OutOfMemory, OutOfMemory,
PermissionDenied,
ReadOnly, ReadOnly,
TimedOut, TimedOut,
TooManyDescriptors, TooManyDescriptors,

View File

@ -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)] #[derive(Clone, Default)]
pub struct FdSet { pub struct FdSet {
bits: [u64; 2] bits: [u64; 2]

View File

@ -2,7 +2,8 @@ pub use libsys::signal::{Signal, SignalDestination};
pub use libsys::proc::ExitCode; pub use libsys::proc::ExitCode;
pub use libsys::termios; pub use libsys::termios;
pub use libsys::calls::*; 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}; use core::sync::atomic::{Ordering, AtomicBool};

View File

@ -13,6 +13,10 @@ path = "src/init/main.rs"
name = "shell" name = "shell"
path = "src/shell/main.rs" path = "src/shell/main.rs"
[[bin]]
name = "fuzzy"
path = "src/fuzzy/main.rs"
[dependencies] [dependencies]
libusr = { path = "../libusr" } libusr = { path = "../libusr" }
lazy_static = { version = "*", features = ["spin_no_std"] } lazy_static = { version = "*", features = ["spin_no_std"] }

10
user/src/fuzzy/main.rs Normal file
View File

@ -0,0 +1,10 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate libusr;
#[no_mangle]
fn main() -> i32 {
0
}

View File

@ -3,34 +3,56 @@
#[macro_use] #[macro_use]
extern crate libusr; extern crate libusr;
#[macro_use] extern crate alloc;
extern crate lazy_static;
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::io::{self, Read};
use libusr::sys::{Signal, SignalDestination};
use libusr::sync::Mutex;
fn sleep(ns: u64) { fn readline<'a, F: Read>(f: &mut F, bytes: &'a mut [u8]) -> Result<Option<&'a str>, io::Error> {
let mut rem = [0; 2]; let size = f.read(bytes)?;
libusr::sys::sys_ex_nanosleep(ns, &mut rem).unwrap(); 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] #[no_mangle]
fn main() -> i32 { fn main() -> i32 {
let value = 1234; let mut buf = [0; 256];
let thread = thread::spawn(move || { let mut stdin = io::stdin();
trace!("Closure is alive: {}", value);
sleep(2_000_000_000);
trace!("Closure will now exit");
value - 100 loop {
}); print!("> ");
sleep(1_000_000_000); let line = readline(&mut stdin, &mut buf).unwrap();
if line.is_none() {
trace!("???"); break;
}
trace!("Thread joined: {:?}", thread.join()); let line = line.unwrap().trim_start_matches(' ');
if line.is_empty() {
continue;
}
execute(line);
}
0 0
} }