VFS: path resolution

master
TheOddGarlic 2022-08-07 15:35:55 +03:00
parent fa45737901
commit f67e9b2372
7 changed files with 325 additions and 250 deletions

View File

@ -9,9 +9,12 @@ pub enum FsError {
EndOfFile, EndOfFile,
InodeNotFound, InodeNotFound,
InvalidDevice, InvalidDevice,
InvalidPath,
IsDirectory, IsDirectory,
NotAbsolute,
NotADirectory, NotADirectory,
NotFound, NotFound,
Recursion,
UnsupportedOperation, UnsupportedOperation,
} }

View File

@ -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 {

View File

@ -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()));
} }
} }
} }

View File

@ -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,

View File

@ -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)
} }
} }

View File

@ -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();

View File

@ -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`")
} }