forked from koniifer/ableos
VFS: path resolution
This commit is contained in:
parent
960da43383
commit
0cc1aaa64f
|
@ -9,9 +9,12 @@ pub enum FsError {
|
||||||
EndOfFile,
|
EndOfFile,
|
||||||
InodeNotFound,
|
InodeNotFound,
|
||||||
InvalidDevice,
|
InvalidDevice,
|
||||||
|
InvalidPath,
|
||||||
IsDirectory,
|
IsDirectory,
|
||||||
|
NotAbsolute,
|
||||||
NotADirectory,
|
NotADirectory,
|
||||||
NotFound,
|
NotFound,
|
||||||
|
Recursion,
|
||||||
UnsupportedOperation,
|
UnsupportedOperation,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ use ext2::volume::Volume;
|
||||||
use crate::handle::{Handle, HandleResource};
|
use crate::handle::{Handle, HandleResource};
|
||||||
|
|
||||||
use super::errors::FsError;
|
use super::errors::FsError;
|
||||||
use super::vfs::{DirectoryEntry, FsFlags, VFS};
|
use super::vfs::{DirectoryEntry, FsFlags, VirtualFileSystem, VFS};
|
||||||
use super::{FsNode, FsResult as Result, StorageDevice};
|
use super::{FsNode, FsResult as Result, StorageDevice};
|
||||||
|
|
||||||
pub struct Ext2StorageDevice<S, V>
|
pub struct Ext2StorageDevice<S, V>
|
||||||
|
@ -23,7 +23,7 @@ where
|
||||||
{
|
{
|
||||||
fs: Synced<Ext2<S, V>>,
|
fs: Synced<Ext2<S, V>>,
|
||||||
device_handle: Handle,
|
device_handle: Handle,
|
||||||
root: Arc<FsNode>,
|
root_handle: Handle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, V> Ext2StorageDevice<S, V>
|
impl<S, V> Ext2StorageDevice<S, V>
|
||||||
|
@ -43,13 +43,13 @@ where
|
||||||
Weak::new(),
|
Weak::new(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let mut vfs = VFS.lock();
|
let mut vfs = VFS.write();
|
||||||
vfs.add_fs_node(root.clone());
|
let root_handle = vfs.add_fs_node(root.clone());
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
fs,
|
fs,
|
||||||
device_handle,
|
device_handle,
|
||||||
root,
|
root_handle,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ where
|
||||||
.fs
|
.fs
|
||||||
.inode_nth(entry.inode)
|
.inode_nth(entry.inode)
|
||||||
.ok_or_else(|| FsError::InodeNotFound)?;
|
.ok_or_else(|| FsError::InodeNotFound)?;
|
||||||
let mut vfs = VFS.lock();
|
let mut vfs = VFS.write();
|
||||||
let entry_node_handle = vfs
|
let entry_node_handle = vfs
|
||||||
.find_fs_node(entry.inode, self.device_handle)
|
.find_fs_node(entry.inode, self.device_handle)
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
|
@ -113,14 +113,13 @@ where
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_dir(&self, node: &FsNode, name: &str) -> Result<Handle> {
|
fn find_dir(&self, vfs: &mut VirtualFileSystem, node: &FsNode, name: &str) -> Result<Handle> {
|
||||||
let inode = self
|
let inode = self
|
||||||
.fs
|
.fs
|
||||||
.inode_nth(node.inode() as usize)
|
.inode_nth(node.inode() as usize)
|
||||||
.ok_or_else(|| FsError::InodeNotFound)?;
|
.ok_or_else(|| FsError::InodeNotFound)?;
|
||||||
let dir = inode.directory().ok_or_else(|| FsError::NotADirectory)?;
|
let dir = inode.directory().ok_or_else(|| FsError::NotADirectory)?;
|
||||||
let mut found_node = Err(FsError::NotFound);
|
let mut found_node = Err(FsError::NotFound);
|
||||||
let mut vfs = VFS.lock();
|
|
||||||
for entry in dir {
|
for entry in dir {
|
||||||
if entry.is_err() {
|
if entry.is_err() {
|
||||||
continue;
|
continue;
|
||||||
|
@ -139,14 +138,15 @@ where
|
||||||
Weak::new(),
|
Weak::new(),
|
||||||
)))
|
)))
|
||||||
}));
|
}));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
found_node
|
found_node
|
||||||
}
|
}
|
||||||
|
|
||||||
fn root_node(&self) -> Arc<FsNode> {
|
fn root(&self) -> Handle {
|
||||||
self.root.clone()
|
self.root_handle
|
||||||
}
|
}
|
||||||
|
|
||||||
fn device_handle(&self) -> Handle {
|
fn device_handle(&self) -> Handle {
|
||||||
|
|
|
@ -16,7 +16,7 @@ use crate::{filesystem::vfs::VFS, handle::Handle, KERNEL_STATE};
|
||||||
use self::{
|
use self::{
|
||||||
errors::FsError,
|
errors::FsError,
|
||||||
ext2::Ext2StorageDevice,
|
ext2::Ext2StorageDevice,
|
||||||
vfs::{DirectoryEntry, FsNode},
|
vfs::{DirectoryEntry, FsNode, VirtualFileSystem},
|
||||||
};
|
};
|
||||||
use FsResult as Result;
|
use FsResult as Result;
|
||||||
|
|
||||||
|
@ -30,18 +30,18 @@ where
|
||||||
fn read(&self, node: &FsNode, offset: usize, size: usize, buffer: &mut Vec<u8>) -> Result<()>;
|
fn read(&self, node: &FsNode, offset: usize, size: usize, buffer: &mut Vec<u8>) -> Result<()>;
|
||||||
fn write(&self, node: &FsNode, offset: usize, buffer: &[u8]) -> Result<()>;
|
fn write(&self, node: &FsNode, offset: usize, buffer: &[u8]) -> Result<()>;
|
||||||
fn read_dir(&self, node: &FsNode, index: usize) -> Result<DirectoryEntry>;
|
fn read_dir(&self, node: &FsNode, index: usize) -> Result<DirectoryEntry>;
|
||||||
fn find_dir(&self, node: &FsNode, name: &str) -> Result<Handle>;
|
fn find_dir(&self, vfs: &mut VirtualFileSystem, node: &FsNode, name: &str) -> Result<Handle>;
|
||||||
// TODO: flush to disk
|
// TODO: flush to disk
|
||||||
|
|
||||||
fn root_node(&self) -> Arc<FsNode>;
|
fn root(&self) -> Handle;
|
||||||
fn device_handle(&self) -> Handle;
|
fn device_handle(&self) -> Handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() -> Result<()> {
|
pub fn init() -> Result<()> {
|
||||||
let mut state = KERNEL_STATE.lock();
|
let mut state = KERNEL_STATE.lock();
|
||||||
let fs = load_fs()?;
|
let fs = load_fs()?;
|
||||||
let mut vfs = VFS.lock();
|
let mut vfs = VFS.write();
|
||||||
vfs.init(fs.root_node());
|
vfs.set_root(fs.root())?;
|
||||||
state.add_storage_device(fs);
|
state.add_storage_device(fs);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -53,19 +53,37 @@ fn load_fs() -> Result<Ext2StorageDevice<Size1024, Vec<u8>>> {
|
||||||
Ext2StorageDevice::new(volume)
|
Ext2StorageDevice::new(volume)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk<S: Into<String>>(dir: Arc<FsNode>, path: S) {
|
pub fn tree(path: &str) -> Result<()> {
|
||||||
|
let dir = {
|
||||||
|
let mut vfs = VFS.write();
|
||||||
|
let handle = vfs.resolve(path)?;
|
||||||
|
vfs.fs_node(handle).ok_or_else(|| FsError::NotFound)?
|
||||||
|
};
|
||||||
|
|
||||||
|
tree_inner(
|
||||||
|
dir,
|
||||||
|
if path.starts_with('/') {
|
||||||
|
&path[1..]
|
||||||
|
} else {
|
||||||
|
path
|
||||||
|
},
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tree_inner<S: Into<String>>(dir: Arc<FsNode>, path: S) {
|
||||||
let path = path.into();
|
let path = path.into();
|
||||||
if let Some(dir) = dir.directory() {
|
if let Some(dir) = dir.directory() {
|
||||||
for entry in dir {
|
for entry in dir {
|
||||||
let fs_node = {
|
let fs_node = {
|
||||||
let mut vfs = VFS.lock();
|
let vfs = VFS.read();
|
||||||
vfs.fs_node(entry.node()).unwrap()
|
vfs.fs_node(entry.node()).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("{}/{} => {}", path, entry.name(), fs_node.inode());
|
println!("{}/{} => {}", path, entry.name(), fs_node.inode());
|
||||||
trace!("{entry:#?}");
|
trace!("{entry:#?}");
|
||||||
if entry.name() != "." && entry.name() != ".." {
|
if entry.name() != "." && entry.name() != ".." {
|
||||||
walk(fs_node, format!("{}/{}", path, entry.name()));
|
tree_inner(fs_node, format!("{}/{}", path, entry.name()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use core::cmp;
|
||||||
use alloc::sync::{Arc, Weak};
|
use alloc::sync::{Arc, Weak};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use spin::Mutex;
|
use spin::RwLock;
|
||||||
|
|
||||||
use super::{errors::FsError, FsResult as Result};
|
use super::{errors::FsError, FsResult as Result};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -17,18 +17,77 @@ use crate::{
|
||||||
KERNEL_STATE,
|
KERNEL_STATE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The limit for symlink recursion. In POSIX, this is at least 8. In Linux, this is 40.
|
||||||
|
const SYMLINK_RECURSION_LIMIT: u8 = 8;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref VFS: Mutex<VirtualFileSystem> = Default::default();
|
pub static ref VFS: RwLock<VirtualFileSystem> = Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VirtualFileSystem {
|
pub struct VirtualFileSystem {
|
||||||
fs_nodes: HashMap<Handle, Arc<FsNode>>,
|
fs_nodes: HashMap<Handle, Arc<FsNode>>,
|
||||||
root_node: Weak<FsNode>,
|
root_node: Weak<FsNode>,
|
||||||
|
root_handle: Option<Handle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtualFileSystem {
|
impl VirtualFileSystem {
|
||||||
pub fn init(&mut self, root_node: Arc<FsNode>) {
|
/// Sets the VFS root to the given VFS node handle.
|
||||||
self.root_node = Arc::downgrade(&root_node)
|
pub fn set_root(&mut self, handle: Handle) -> Result<()> {
|
||||||
|
let root_node = self.fs_node(handle).ok_or_else(|| FsError::NotFound)?;
|
||||||
|
self.root_node = Arc::downgrade(&root_node);
|
||||||
|
self.root_handle = Some(handle);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves the path to a handle. If the resulting node is a symlink,
|
||||||
|
/// the symlink itself is returned. All symlinks but the resulting node
|
||||||
|
/// are traversed.
|
||||||
|
///
|
||||||
|
/// Requires a mutable reference because internally it might open new VFS
|
||||||
|
/// nodes while resolving the path.
|
||||||
|
pub fn resolve<S: AsRef<str>>(&mut self, path: S) -> Result<Handle> {
|
||||||
|
// TODO: caching
|
||||||
|
let path = path.as_ref();
|
||||||
|
|
||||||
|
if !path.starts_with('/') {
|
||||||
|
// FIXME: use current process working directory for relative paths?
|
||||||
|
Err(FsError::NotAbsolute)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut components = path.split_terminator(path);
|
||||||
|
components.next(); // throw the empty string caused by the root /
|
||||||
|
// will be initialised beforehand so okay to unwrap
|
||||||
|
let mut resolved_node = self.root_handle.unwrap();
|
||||||
|
// let mut symlink_recursion_level = 0;
|
||||||
|
for component in components {
|
||||||
|
// if symlink_recursion_level >= SYMLINK_RECURSION_LIMIT {
|
||||||
|
// Err(FsError::Recursion)?;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if component == "" {
|
||||||
|
Err(FsError::InvalidPath)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// checked by previous iteration so okay to unwrap
|
||||||
|
let parent = self.fs_node(resolved_node).unwrap();
|
||||||
|
|
||||||
|
// TODO: permission checks
|
||||||
|
|
||||||
|
// FIXME: find_dir checks that this is a directory already but
|
||||||
|
// that's just more boilerplate in StorageDevice impls
|
||||||
|
// we should probably check that here instead to reduce
|
||||||
|
// required boilerplate
|
||||||
|
// if !parent.is_dir() {
|
||||||
|
// Err(FsError::NotADirectory)?;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// FIXME: handle mount points
|
||||||
|
// FIXME: handle symlinks
|
||||||
|
|
||||||
|
resolved_node = parent.find_dir(self, component)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(resolved_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_fs_node(&mut self, fs_node: Arc<FsNode>) -> Handle {
|
pub fn add_fs_node(&mut self, fs_node: Arc<FsNode>) -> Handle {
|
||||||
|
@ -47,7 +106,7 @@ impl VirtualFileSystem {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fs_node(&mut self, handle: Handle) -> Option<Arc<FsNode>> {
|
pub fn fs_node(&self, handle: Handle) -> Option<Arc<FsNode>> {
|
||||||
self.fs_nodes.get(&handle).cloned()
|
self.fs_nodes.get(&handle).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +121,7 @@ impl Default for VirtualFileSystem {
|
||||||
Self {
|
Self {
|
||||||
fs_nodes: HashMap::new(),
|
fs_nodes: HashMap::new(),
|
||||||
root_node: Weak::new(),
|
root_node: Weak::new(),
|
||||||
|
root_handle: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,13 +211,13 @@ impl FsNode {
|
||||||
device.read_dir(self, index)
|
device.read_dir(self, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_dir(&self, name: &str) -> Result<Handle> {
|
pub fn find_dir(&self, vfs: &mut VirtualFileSystem, name: &str) -> Result<Handle> {
|
||||||
let state = KERNEL_STATE.lock();
|
let state = KERNEL_STATE.lock();
|
||||||
let device = state
|
let device = state
|
||||||
.storage_device(self.device_handle)
|
.storage_device(self.device_handle)
|
||||||
.ok_or_else(|| FsError::InvalidDevice)?;
|
.ok_or_else(|| FsError::InvalidDevice)?;
|
||||||
|
|
||||||
device.find_dir(self, name)
|
device.find_dir(vfs, self, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn directory(self: Arc<Self>) -> Option<Directory> {
|
pub fn directory(self: Arc<Self>) -> Option<Directory> {
|
||||||
|
@ -220,7 +280,7 @@ impl Iterator for Directory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DirectoryEntry {
|
pub struct DirectoryEntry {
|
||||||
name: String,
|
name: String,
|
||||||
node: Handle,
|
node: Handle,
|
||||||
|
|
|
@ -5,57 +5,57 @@ use core::fmt::{Display, Error, Formatter};
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct Kilosecond(u32);
|
pub struct Kilosecond(u32);
|
||||||
impl Kilosecond {
|
impl Kilosecond {
|
||||||
pub fn from_ms(ms: u32) -> Self {
|
pub fn from_ms(ms: u32) -> Self {
|
||||||
Self(ms)
|
Self(ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_sec(sec: u32) -> Self {
|
pub fn from_sec(sec: u32) -> Self {
|
||||||
Self(sec * 1000)
|
Self(sec * 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_minutes(min: u32) -> Self {
|
pub fn from_minutes(min: u32) -> Self {
|
||||||
Self(min * 60 * 1000)
|
Self(min * 60 * 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_hours(hrs: u32) -> Self {
|
pub fn from_hours(hrs: u32) -> Self {
|
||||||
Self(hrs * 60 * 60 * 1000)
|
Self(hrs * 60 * 60 * 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_days(days: u32) -> Self {
|
pub fn from_days(days: u32) -> Self {
|
||||||
Self(days * 24 * 60 * 60 * 1000)
|
Self(days * 24 * 60 * 60 * 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn s(&self) -> u32 {
|
pub fn s(&self) -> u32 {
|
||||||
(self.0 % 1000)
|
(self.0 % 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn k(&self) -> u32 {
|
pub fn k(&self) -> u32 {
|
||||||
self.0 / 1000
|
self.0 / 1000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Kilosecond {
|
impl Display for Kilosecond {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
write![f, "{}K {}S", self.k(), self.s()]
|
write![f, "{}K {}S", self.k(), self.s()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::ops::Add for Kilosecond {
|
impl core::ops::Add for Kilosecond {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
fn add(self, rhs: Self) -> Self {
|
fn add(self, rhs: Self) -> Self {
|
||||||
Self(self.0 + rhs.0)
|
Self(self.0 + rhs.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::ops::Sub for Kilosecond {
|
impl core::ops::Sub for Kilosecond {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
fn sub(self, rhs: Self) -> Self {
|
fn sub(self, rhs: Self) -> Self {
|
||||||
Self(self.0 - rhs.0)
|
Self(self.0 - rhs.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Time> for Kilosecond {
|
impl From<Time> for Kilosecond {
|
||||||
fn from(t: Time) -> Self {
|
fn from(t: Time) -> Self {
|
||||||
Self((t.hour as u32 * 3600 + t.minutes as u32 * 60 + t.seconds as u32) * 1000)
|
Self((t.hour as u32 * 3600 + t.minutes as u32 * 60 + t.seconds as u32) * 1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,14 @@
|
||||||
use crate::arch::drivers::sysinfo::master;
|
use crate::arch::drivers::sysinfo::master;
|
||||||
use crate::arch::interrupts::{reset_pit_for_cpu, set_pit_2};
|
use crate::arch::interrupts::{reset_pit_for_cpu, set_pit_2};
|
||||||
use crate::devices::pci::brute_force_scan;
|
use crate::devices::pci::brute_force_scan;
|
||||||
use crate::filesystem::vfs::VFS;
|
use crate::filesystem;
|
||||||
use crate::systeminfo::{KERNEL_VERSION, RELEASE_TYPE};
|
use crate::systeminfo::{KERNEL_VERSION, RELEASE_TYPE};
|
||||||
use crate::time::fetch_time;
|
use crate::time::fetch_time;
|
||||||
use crate::{filesystem, KERNEL_STATE};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::shutdown,
|
arch::shutdown,
|
||||||
rhai_shell::KEYBUFF,
|
rhai_shell::KEYBUFF,
|
||||||
vterm::VTerm,
|
vterm::VTerm,
|
||||||
|
KERNEL_STATE,
|
||||||
// wasm_jumploader::run_program,
|
// wasm_jumploader::run_program,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ pub fn scratchpad() {
|
||||||
|
|
||||||
disable();
|
disable();
|
||||||
let tick_time = fetch_time();
|
let tick_time = fetch_time();
|
||||||
let hostname = &KERNEL_STATE.lock().hostname;
|
let hostname = KERNEL_STATE.lock().hostname.clone();
|
||||||
|
|
||||||
let allocator = ALLOCATOR.lock();
|
let allocator = ALLOCATOR.lock();
|
||||||
let size = allocator.size();
|
let size = allocator.size();
|
||||||
|
@ -122,13 +122,6 @@ pub fn scratchpad() {
|
||||||
BANNER_WIDTH
|
BANNER_WIDTH
|
||||||
);
|
);
|
||||||
|
|
||||||
let root = {
|
|
||||||
let vfs = VFS.lock();
|
|
||||||
vfs.root_node()
|
|
||||||
};
|
|
||||||
|
|
||||||
filesystem::walk(root, "");
|
|
||||||
|
|
||||||
real_shell();
|
real_shell();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,6 +241,7 @@ pub fn command_parser(user: String, command: String) {
|
||||||
// }
|
// }
|
||||||
"test" => {}
|
"test" => {}
|
||||||
"quit" => shutdown(),
|
"quit" => shutdown(),
|
||||||
|
"tree" => filesystem::tree("/").unwrap(),
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
// let mut options = OpenOptions::new();
|
// let mut options = OpenOptions::new();
|
||||||
|
|
|
@ -10,213 +10,213 @@ use std::{fs, process::Command};
|
||||||
use colored::*;
|
use colored::*;
|
||||||
|
|
||||||
struct Options {
|
struct Options {
|
||||||
pub subcommand: Subcommand,
|
pub subcommand: Subcommand,
|
||||||
pub arguments: Vec<String>,
|
pub arguments: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Subcommand {
|
enum Subcommand {
|
||||||
Doc,
|
Doc,
|
||||||
Help,
|
Help,
|
||||||
Run,
|
Run,
|
||||||
Empty,
|
Empty,
|
||||||
/// Run all tests for all architectures
|
/// Run all tests for all architectures
|
||||||
Test,
|
Test,
|
||||||
Unknown(String),
|
Unknown(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Subcommand {
|
impl Subcommand {
|
||||||
fn from_str<S: AsRef<str>>(str: S) -> Subcommand {
|
fn from_str<S: AsRef<str>>(str: S) -> Subcommand {
|
||||||
match str.as_ref() {
|
match str.as_ref() {
|
||||||
"doc" => Subcommand::Doc,
|
"doc" => Subcommand::Doc,
|
||||||
"help" => Subcommand::Help,
|
"help" => Subcommand::Help,
|
||||||
"run" | "r" => Subcommand::Run,
|
"run" | "r" => Subcommand::Run,
|
||||||
"test" | "t" => Subcommand::Test,
|
"test" | "t" => Subcommand::Test,
|
||||||
"" => Subcommand::Empty,
|
"" => Subcommand::Empty,
|
||||||
unknown => Subcommand::Unknown(unknown.to_string()),
|
unknown => Subcommand::Unknown(unknown.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MachineType {
|
enum MachineType {
|
||||||
X86_64,
|
X86_64,
|
||||||
RiscV64,
|
RiscV64,
|
||||||
AArch64,
|
AArch64,
|
||||||
Unknown(String),
|
Unknown(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let options = options();
|
let options = options();
|
||||||
|
|
||||||
match options.subcommand {
|
match options.subcommand {
|
||||||
Subcommand::Test => {
|
Subcommand::Test => {
|
||||||
Command::new("cargo")
|
Command::new("cargo")
|
||||||
.args(["test", "--target=json_targets/x86_64-ableos.json"])
|
.args(["test", "--target=json_targets/x86_64-ableos.json"])
|
||||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||||
.status()
|
.status()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// panic!("Test Infrastructure missing");
|
// panic!("Test Infrastructure missing");
|
||||||
}
|
}
|
||||||
Subcommand::Doc => {
|
Subcommand::Doc => {
|
||||||
let machine_text = options.arguments.get(0).cloned().unwrap_or_default();
|
let machine_text = options.arguments.get(0).cloned().unwrap_or_default();
|
||||||
|
|
||||||
match machine(machine_text) {
|
match machine(machine_text) {
|
||||||
MachineType::X86_64 => {
|
MachineType::X86_64 => {
|
||||||
Command::new("cargo")
|
Command::new("cargo")
|
||||||
.args(["doc", "--open"])
|
.args(["doc", "--open"])
|
||||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||||
.status()
|
.status()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
}
|
||||||
|
MachineType::RiscV64 => {
|
||||||
|
Command::new("cargo")
|
||||||
|
.args(["doc", "--open", "--target=riscv64gc-unknown-none-elf"])
|
||||||
|
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||||
|
.status()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
MachineType::AArch64 => {
|
||||||
|
Command::new("cargo")
|
||||||
|
.args(["doc", "--open", "--target=json_targets/aarch64-ableos.json"])
|
||||||
|
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||||
|
.status()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
MachineType::Unknown(unknown) => {
|
||||||
|
eprintln!(
|
||||||
|
"{}: unknown machine type `{}`",
|
||||||
|
"error".red().bold(),
|
||||||
|
unknown.bold(),
|
||||||
|
);
|
||||||
|
eprintln!("expected one of x86_64, riscv64 or aarch64");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
MachineType::RiscV64 => {
|
}
|
||||||
Command::new("cargo")
|
Subcommand::Help => help(),
|
||||||
.args(["doc", "--open", "--target=riscv64gc-unknown-none-elf"])
|
Subcommand::Run => {
|
||||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
let machine_text = options.arguments.get(0).cloned().unwrap_or_default();
|
||||||
.status()
|
let debug = options.arguments.get(1).cloned().unwrap_or_default();
|
||||||
.unwrap();
|
let debug = matches!(debug.as_str(), "--debug" | "--dbg" | "-d");
|
||||||
}
|
|
||||||
MachineType::AArch64 => {
|
|
||||||
Command::new("cargo")
|
|
||||||
.args(["doc", "--open", "--target=json_targets/aarch64-ableos.json"])
|
|
||||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
|
||||||
.status()
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
MachineType::Unknown(unknown) => {
|
|
||||||
eprintln!(
|
|
||||||
"{}: unknown machine type `{}`",
|
|
||||||
"error".red().bold(),
|
|
||||||
unknown.bold(),
|
|
||||||
);
|
|
||||||
eprintln!("expected one of x86_64, riscv64 or aarch64");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Subcommand::Help => help(),
|
|
||||||
Subcommand::Run => {
|
|
||||||
let machine_text = options.arguments.get(0).cloned().unwrap_or_default();
|
|
||||||
let debug = options.arguments.get(1).cloned().unwrap_or_default();
|
|
||||||
let debug = matches!(debug.as_str(), "--debug" | "--dbg" | "-d");
|
|
||||||
|
|
||||||
match machine(machine_text) {
|
match machine(machine_text) {
|
||||||
MachineType::X86_64 if debug => {
|
MachineType::X86_64 if debug => {
|
||||||
Command::new("cargo")
|
Command::new("cargo")
|
||||||
.args(["run", "--", "-S", "-gdb", "tcp:9000"])
|
.args(["run", "--", "-S", "-gdb", "tcp:9000"])
|
||||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||||
.status()
|
.status()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
MachineType::X86_64 => {
|
MachineType::X86_64 => {
|
||||||
Command::new("cargo")
|
Command::new("cargo")
|
||||||
.args(["run", "--release"])
|
.args(["run", "--release"])
|
||||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||||
.status()
|
.status()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
MachineType::RiscV64 if debug => {
|
MachineType::RiscV64 if debug => {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"{}: debug is not implemented for riscv64",
|
"{}: debug is not implemented for riscv64",
|
||||||
"error".red().bold()
|
"error".red().bold()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
MachineType::RiscV64 => {
|
MachineType::RiscV64 => {
|
||||||
Command::new("cargo")
|
Command::new("cargo")
|
||||||
.args(["build", "--release", "--target=riscv64gc-unknown-none-elf"])
|
.args(["build", "--release", "--target=riscv64gc-unknown-none-elf"])
|
||||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||||
.status()
|
.status()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Command::new("qemu-system-riscv64")
|
Command::new("qemu-system-riscv64")
|
||||||
.args(["-machine", "virt"])
|
.args(["-machine", "virt"])
|
||||||
.args(["-cpu", "rv64"])
|
.args(["-cpu", "rv64"])
|
||||||
.args(["-smp", "8"])
|
.args(["-smp", "8"])
|
||||||
.args(["-m", "128M"])
|
.args(["-m", "128M"])
|
||||||
.arg("-bios")
|
.arg("-bios")
|
||||||
.arg("src/arch/riscv/firmwear/opensbi-riscv64-generic-fw_jump.bin")
|
.arg("src/arch/riscv/firmwear/opensbi-riscv64-generic-fw_jump.bin")
|
||||||
.arg("-kernel")
|
.arg("-kernel")
|
||||||
.arg("target/riscv64gc-unknown-none-elf/release/ableos")
|
.arg("target/riscv64gc-unknown-none-elf/release/ableos")
|
||||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||||
.status()
|
.status()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
MachineType::AArch64 if debug => {
|
MachineType::AArch64 if debug => {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"{}: debug is not implemented for aarch64",
|
"{}: debug is not implemented for aarch64",
|
||||||
"error".red().bold()
|
"error".red().bold()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
MachineType::AArch64 => {
|
MachineType::AArch64 => {
|
||||||
Command::new("cargo")
|
Command::new("cargo")
|
||||||
.args([
|
.args([
|
||||||
"build",
|
"build",
|
||||||
"--release",
|
"--release",
|
||||||
"--target=json_targets/aarch64-ableos.json",
|
"--target=json_targets/aarch64-ableos.json",
|
||||||
])
|
])
|
||||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||||
.status()
|
.status()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Command::new("qemu-system-aarch64")
|
Command::new("qemu-system-aarch64")
|
||||||
.args(["-machine", "virt"])
|
.args(["-machine", "virt"])
|
||||||
.args(["-m", "1024M"])
|
.args(["-m", "1024M"])
|
||||||
.args(["-cpu", "cortex-a53"])
|
.args(["-cpu", "cortex-a53"])
|
||||||
.args(["-kernel", "target/aarch64-ableos/release/ableos"])
|
.args(["-kernel", "target/aarch64-ableos/release/ableos"])
|
||||||
.args(["-device", "virtio-keyboard"])
|
.args(["-device", "virtio-keyboard"])
|
||||||
.current_dir(fs::canonicalize("./ableos").unwrap())
|
.current_dir(fs::canonicalize("./ableos").unwrap())
|
||||||
.status()
|
.status()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
}
|
||||||
|
MachineType::Unknown(unknown) => {
|
||||||
|
eprintln!(
|
||||||
|
"{}: unknown machine type `{}`",
|
||||||
|
"error".red().bold(),
|
||||||
|
unknown.bold(),
|
||||||
|
);
|
||||||
|
eprintln!("expected one of x86_64, riscv64 or aarch64");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
MachineType::Unknown(unknown) => {
|
}
|
||||||
eprintln!(
|
Subcommand::Empty => {
|
||||||
"{}: unknown machine type `{}`",
|
eprintln!("{}: no subcommand passed", "error".red().bold());
|
||||||
"error".red().bold(),
|
help();
|
||||||
unknown.bold(),
|
}
|
||||||
);
|
Subcommand::Unknown(unknown) => {
|
||||||
eprintln!("expected one of x86_64, riscv64 or aarch64");
|
eprintln!(
|
||||||
}
|
"{}: unknown subcommand `{}`",
|
||||||
}
|
"error".red().bold(),
|
||||||
}
|
unknown.bold()
|
||||||
Subcommand::Empty => {
|
);
|
||||||
eprintln!("{}: no subcommand passed", "error".red().bold());
|
help();
|
||||||
help();
|
}
|
||||||
}
|
}
|
||||||
Subcommand::Unknown(unknown) => {
|
|
||||||
eprintln!(
|
|
||||||
"{}: unknown subcommand `{}`",
|
|
||||||
"error".red().bold(),
|
|
||||||
unknown.bold()
|
|
||||||
);
|
|
||||||
help();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn options() -> Options {
|
fn options() -> Options {
|
||||||
let subcommand = std::env::args().nth(1).unwrap_or_default();
|
let subcommand = std::env::args().nth(1).unwrap_or_default();
|
||||||
let arguments = std::env::args().skip(2).collect();
|
let arguments = std::env::args().skip(2).collect();
|
||||||
|
|
||||||
Options {
|
Options {
|
||||||
subcommand: Subcommand::from_str(subcommand),
|
subcommand: Subcommand::from_str(subcommand),
|
||||||
arguments,
|
arguments,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn machine<S: AsRef<str>>(text: S) -> MachineType {
|
fn machine<S: AsRef<str>>(text: S) -> MachineType {
|
||||||
match text.as_ref() {
|
match text.as_ref() {
|
||||||
"x86" | "x86_64" => MachineType::X86_64,
|
"x86" | "x86_64" => MachineType::X86_64,
|
||||||
"riscv" | "riscv64" => MachineType::RiscV64,
|
"riscv" | "riscv64" => MachineType::RiscV64,
|
||||||
"arm" | "arm64" | "aarch64" => MachineType::AArch64,
|
"arm" | "arm64" | "aarch64" => MachineType::AArch64,
|
||||||
"" => {
|
"" => {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"{}: no machine type passed, defaulting to x86_64",
|
"{}: no machine type passed, defaulting to x86_64",
|
||||||
"warning".yellow().bold()
|
"warning".yellow().bold()
|
||||||
);
|
);
|
||||||
MachineType::X86_64
|
MachineType::X86_64
|
||||||
}
|
}
|
||||||
unknown => MachineType::Unknown(unknown.to_string()),
|
unknown => MachineType::Unknown(unknown.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn help() {
|
fn help() {
|
||||||
todo!("`help`")
|
todo!("`help`")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue