fs/libc: implement some libc functions, fix file times
This commit is contained in:
parent
fd0e2cc229
commit
8ffc223a2b
@ -5,6 +5,7 @@ use libk::vfs::Metadata;
|
||||
use yggdrasil_abi::{
|
||||
bitflags,
|
||||
io::{FileMode, FileType, GroupId, UserId},
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
use crate::Ext2Fs;
|
||||
@ -253,8 +254,9 @@ impl Inode {
|
||||
inode: Some(ino),
|
||||
block_count: self.blocks(fs) as _,
|
||||
block_size: fs.block_size as _,
|
||||
ctime: self.ctime as _,
|
||||
mtime: self.mtime as _,
|
||||
ctime: SystemTime::from_seconds(self.ctime as u64),
|
||||
mtime: SystemTime::from_seconds(self.mtime as u64),
|
||||
atime: SystemTime::from_seconds(self.atime as u64),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -176,9 +176,9 @@ impl InodeAccess {
|
||||
.map_err(|_| Error::InvalidArgument)?;
|
||||
|
||||
self.map_mut(|inode| {
|
||||
inode.mtime = metadata.mtime as _;
|
||||
inode.atime = metadata.mtime as _;
|
||||
inode.ctime = metadata.ctime as _;
|
||||
inode.mtime = metadata.mtime.seconds() as u32;
|
||||
inode.atime = metadata.mtime.seconds() as u32;
|
||||
inode.ctime = metadata.ctime.seconds() as u32;
|
||||
|
||||
inode.mode.update_permissions(metadata.mode);
|
||||
inode.uid = uid;
|
||||
|
@ -15,6 +15,7 @@ use libk_util::{
|
||||
};
|
||||
use yggdrasil_abi::{
|
||||
io::{DirectoryEntry, FileMode, GroupId, UserId},
|
||||
time::SystemTime,
|
||||
util::FixedString,
|
||||
};
|
||||
|
||||
@ -254,8 +255,10 @@ impl DirectoryNode {
|
||||
FileMode::default_file()
|
||||
},
|
||||
inode: Some(cluster.0),
|
||||
ctime: 0,
|
||||
mtime: 0,
|
||||
// TODO
|
||||
ctime: SystemTime::ZERO,
|
||||
mtime: SystemTime::ZERO,
|
||||
atime: SystemTime::ZERO,
|
||||
block_count: (size.div_ceil(self.fs.layout.bytes_per_sector as u32)) as u64,
|
||||
block_size: self.fs.layout.bytes_per_sector as u64,
|
||||
};
|
||||
|
@ -10,7 +10,10 @@ use libk::{
|
||||
vfs::{Filesystem, FilesystemMountOption, Metadata, Node, NodeFlags, NodeRef},
|
||||
};
|
||||
use libk_util::get_le_u32;
|
||||
use yggdrasil_abi::io::{FileMode, GroupId, UserId};
|
||||
use yggdrasil_abi::{
|
||||
io::{FileMode, GroupId, UserId},
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
@ -64,8 +67,10 @@ impl Fat32Fs {
|
||||
uid: UserId::root(),
|
||||
gid: GroupId::root(),
|
||||
mode: FileMode::default_dir(),
|
||||
ctime: 0,
|
||||
mtime: 0,
|
||||
// TODO
|
||||
ctime: SystemTime::ZERO,
|
||||
mtime: SystemTime::ZERO,
|
||||
atime: SystemTime::ZERO,
|
||||
inode: Some(fs.layout.root_directory_cluster.0),
|
||||
block_size: fs.layout.bytes_per_sector as u64,
|
||||
block_count: 0,
|
||||
|
@ -2,13 +2,14 @@ use alloc::sync::Arc;
|
||||
use core::any::Any;
|
||||
|
||||
use libk::vfs::{CommonImpl, InstanceData, Metadata, Node, NodeFlags, NodeRef, RegularImpl};
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
use libk_util::sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock};
|
||||
use yggdrasil_abi::{error::Error, io::OpenOptions};
|
||||
|
||||
use crate::{block::BlockAllocator, bvec::BVec, MemoryFilesystem};
|
||||
|
||||
pub(crate) struct FileNode<A: BlockAllocator> {
|
||||
pub(crate) data: IrqSafeSpinlock<BVec<'static, A>>,
|
||||
pub(crate) metadata: IrqSafeRwLock<Metadata>,
|
||||
}
|
||||
|
||||
impl<A: BlockAllocator> FileNode<A> {
|
||||
@ -16,9 +17,10 @@ impl<A: BlockAllocator> FileNode<A> {
|
||||
Node::regular(
|
||||
Self {
|
||||
data: IrqSafeSpinlock::new(BVec::new()),
|
||||
metadata: IrqSafeRwLock::new(metadata),
|
||||
},
|
||||
NodeFlags::IN_MEMORY_PROPS,
|
||||
Some(metadata),
|
||||
NodeFlags::empty(),
|
||||
None,
|
||||
Some(fs),
|
||||
)
|
||||
}
|
||||
@ -32,6 +34,15 @@ impl<A: BlockAllocator> CommonImpl for FileNode<A> {
|
||||
fn size(&self, _node: &NodeRef) -> Result<u64, Error> {
|
||||
Ok(self.data.lock().size() as u64)
|
||||
}
|
||||
|
||||
fn metadata(&self, _node: &NodeRef) -> Result<Metadata, Error> {
|
||||
Ok(*self.metadata.read())
|
||||
}
|
||||
|
||||
fn set_metadata(&self, _node: &NodeRef, metadata: &Metadata) -> Result<(), Error> {
|
||||
*self.metadata.write() = *metadata;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: BlockAllocator> RegularImpl for FileNode<A> {
|
||||
@ -55,6 +66,7 @@ impl<A: BlockAllocator> RegularImpl for FileNode<A> {
|
||||
pos: u64,
|
||||
buf: &mut [u8],
|
||||
) -> Result<usize, Error> {
|
||||
self.metadata.write().set_atime_now();
|
||||
self.data.lock().read(pos, buf)
|
||||
}
|
||||
|
||||
@ -65,10 +77,12 @@ impl<A: BlockAllocator> RegularImpl for FileNode<A> {
|
||||
pos: u64,
|
||||
buf: &[u8],
|
||||
) -> Result<usize, Error> {
|
||||
self.metadata.write().set_mtime_now();
|
||||
self.data.lock().write(pos, buf)
|
||||
}
|
||||
|
||||
fn truncate(&self, _node: &NodeRef, new_size: u64) -> Result<(), Error> {
|
||||
self.metadata.write().set_mtime_now();
|
||||
self.data.lock().truncate(new_size)
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ use libk_mm::{phys::GlobalPhysicalAllocator, process::ProcessAddressSpace};
|
||||
use libk_util::{
|
||||
event::{BoolEvent, OneTimeEvent},
|
||||
sync::{
|
||||
spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockWriteGuard},
|
||||
spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockReadGuard, IrqSafeRwLockWriteGuard},
|
||||
IrqSafeSpinlock,
|
||||
},
|
||||
};
|
||||
@ -443,7 +443,7 @@ impl Process {
|
||||
|
||||
if let Some(status) = child.get_exit_status() {
|
||||
log::debug!("Child {id} exited with status {status:?} (didn't block)");
|
||||
// TODO remove child
|
||||
self.inner.write().remove_child(id);
|
||||
return Ok(status);
|
||||
}
|
||||
|
||||
@ -455,7 +455,7 @@ impl Process {
|
||||
loop {
|
||||
if let Some(status) = child.get_exit_status() {
|
||||
log::debug!("Child {id} exited with status {status:?}", );
|
||||
// TODO remove child
|
||||
self.inner.write().remove_child(id);
|
||||
break status;
|
||||
}
|
||||
|
||||
@ -464,13 +464,23 @@ impl Process {
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_any_child_exit(&self) -> Option<(Arc<Process>, IrqSafeRwLockWriteGuard<ProcessInner>)> {
|
||||
let read = self.inner.read();
|
||||
if let Some(child) = read.any_exited_child() {
|
||||
let write = IrqSafeRwLockReadGuard::upgrade(read);
|
||||
Some((child, write))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wait_for_any_child(&self, flags: WaitFlags) -> Result<(ProcessId, ExitCode), Error> {
|
||||
if let Some(child) = self.inner.read().any_exited_child() {
|
||||
if let Some((child, mut guard)) = self.poll_any_child_exit() {
|
||||
let id = child.id;
|
||||
// unwrap ok: ProcessInner tells the child already exited
|
||||
let status = child.get_exit_status().unwrap();
|
||||
log::debug!("Child {id} exited with status {status:?} (didn't block)");
|
||||
// TODO remove child
|
||||
log::info!("Child {id} exited with status {status:?} (didn't block)");
|
||||
guard.remove_child(id);
|
||||
return Ok((id, status));
|
||||
}
|
||||
|
||||
@ -480,12 +490,12 @@ impl Process {
|
||||
|
||||
block! {
|
||||
loop {
|
||||
if let Some(child) = self.inner.read().any_exited_child() {
|
||||
if let Some((child, mut guard)) = self.poll_any_child_exit() {
|
||||
let id = child.id;
|
||||
// unwrap ok: ProcessInner tells the child already exited
|
||||
let status = child.get_exit_status().unwrap();
|
||||
log::debug!("Child {id} exited with status {status:?}", );
|
||||
// TODO remove child
|
||||
log::info!("Child {id} exited with status {status:?}", );
|
||||
guard.remove_child(id);
|
||||
break (id, status);
|
||||
}
|
||||
|
||||
@ -705,6 +715,10 @@ impl ProcessInner {
|
||||
.find(|child| child.has_exited())
|
||||
}
|
||||
|
||||
pub fn remove_child(&mut self, id: ProcessId) -> bool {
|
||||
self.children.remove(&id).is_some()
|
||||
}
|
||||
|
||||
pub fn remove_thread(&mut self, id: ThreadId) -> bool {
|
||||
let n = self.threads.len();
|
||||
self.threads.retain(|t| t.id != id);
|
||||
|
@ -14,8 +14,9 @@ use traits::HardlinkImpl;
|
||||
use yggdrasil_abi::{
|
||||
bitflags,
|
||||
error::Error,
|
||||
io::{FileMode, FileType, GroupId, UserId},
|
||||
io::{FileMetadataUpdate, FileMetadataUpdateMode, FileMode, FileType, GroupId, UserId},
|
||||
path::Path,
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
mod access;
|
||||
@ -126,10 +127,12 @@ pub struct Metadata {
|
||||
pub block_size: u64,
|
||||
/// Size of the node (without metadata) in units of `block_size`
|
||||
pub block_count: u64,
|
||||
/// Creation time (in seconds)
|
||||
pub ctime: u64,
|
||||
/// Modification time (in seconds)
|
||||
pub mtime: u64,
|
||||
/// Creation time
|
||||
pub ctime: SystemTime,
|
||||
/// Modification time
|
||||
pub mtime: SystemTime,
|
||||
/// Last access time
|
||||
pub atime: SystemTime,
|
||||
}
|
||||
|
||||
struct PropertyCache {
|
||||
@ -147,14 +150,17 @@ pub struct Node {
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
pub const MODE_MASK: FileMode = FileMode::new(0o777);
|
||||
|
||||
pub fn now(uid: UserId, gid: GroupId, mode: FileMode, ino: u32) -> Metadata {
|
||||
let now = real_time().seconds();
|
||||
let now = real_time();
|
||||
Metadata {
|
||||
mode,
|
||||
uid,
|
||||
gid,
|
||||
ctime: now,
|
||||
mtime: now,
|
||||
atime: now,
|
||||
inode: Some(ino),
|
||||
block_size: 4096,
|
||||
block_count: 0,
|
||||
@ -164,6 +170,33 @@ impl Metadata {
|
||||
pub fn now_root(mode: FileMode, ino: u32) -> Metadata {
|
||||
Self::now(UserId::root(), GroupId::root(), mode, ino)
|
||||
}
|
||||
|
||||
pub fn set_atime_now(&mut self) {
|
||||
self.atime = real_time();
|
||||
}
|
||||
|
||||
pub fn set_mtime_now(&mut self) {
|
||||
let t = real_time();
|
||||
log::info!("set_mtime_now = {t:?}");
|
||||
self.mtime = t;
|
||||
self.atime = t;
|
||||
}
|
||||
|
||||
pub fn update(&mut self, update: &FileMetadataUpdate) {
|
||||
match update {
|
||||
FileMetadataUpdate::Times(_) => todo!(),
|
||||
FileMetadataUpdate::Permissions(mode) => match *mode {
|
||||
FileMetadataUpdateMode::Set(mode) => {
|
||||
self.mode &= !Self::MODE_MASK;
|
||||
self.mode |= mode & Self::MODE_MASK;
|
||||
}
|
||||
FileMetadataUpdateMode::Modify { set, clear } => {
|
||||
self.mode &= !(clear & Self::MODE_MASK);
|
||||
self.mode |= set & Self::MODE_MASK;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node {
|
||||
|
@ -3,10 +3,7 @@ use core::mem::MaybeUninit;
|
||||
use libk_util::ext::OptionExt;
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
io::{
|
||||
DirectoryEntry, FileMetadataUpdate, FileMetadataUpdateMode, FileMode, GroupId, OpenOptions,
|
||||
UserId,
|
||||
},
|
||||
io::{DirectoryEntry, FileMetadataUpdate, FileMode, GroupId, OpenOptions, UserId},
|
||||
};
|
||||
|
||||
use crate::vfs::{
|
||||
@ -228,70 +225,74 @@ impl Node {
|
||||
return Err(Error::InvalidOperation);
|
||||
}
|
||||
|
||||
let mut cache = self.props.lock();
|
||||
let common = self.data_as_common();
|
||||
if self.flags.contains(NodeFlags::IN_MEMORY_PROPS) {
|
||||
let mut cache = self.props.lock();
|
||||
|
||||
let metadata = cache
|
||||
.metadata
|
||||
.get_or_try_insert_with(|| common.metadata(self))?;
|
||||
let metadata = cache
|
||||
.metadata
|
||||
.get_or_try_insert_with(|| common.metadata(self))?;
|
||||
|
||||
// let mut metadata = self.metadata()?;
|
||||
if let Some(uid) = uid {
|
||||
metadata.uid = uid;
|
||||
}
|
||||
if let Some(gid) = gid {
|
||||
metadata.gid = gid;
|
||||
}
|
||||
if let Some(mode) = mode {
|
||||
metadata.mode = mode;
|
||||
}
|
||||
|
||||
if let Some(uid) = uid {
|
||||
metadata.uid = uid;
|
||||
}
|
||||
if let Some(gid) = gid {
|
||||
metadata.gid = gid;
|
||||
}
|
||||
if let Some(mode) = mode {
|
||||
metadata.mode = mode;
|
||||
}
|
||||
|
||||
if !self.flags.contains(NodeFlags::IN_MEMORY_PROPS) {
|
||||
Ok(())
|
||||
} else {
|
||||
// Update permissions in the real node
|
||||
common.set_metadata(self, metadata)?;
|
||||
let mut metadata = common.metadata(self)?;
|
||||
if let Some(uid) = uid {
|
||||
metadata.uid = uid;
|
||||
}
|
||||
if let Some(gid) = gid {
|
||||
metadata.gid = gid;
|
||||
}
|
||||
if let Some(mode) = mode {
|
||||
metadata.mode &= !Metadata::MODE_MASK;
|
||||
metadata.mode |= mode & Metadata::MODE_MASK;
|
||||
}
|
||||
common.set_metadata(self, &metadata)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the "metadata" of the file: uid, gid, access mode
|
||||
pub fn metadata(self: &NodeRef) -> Result<Metadata, Error> {
|
||||
let mut cache = self.props.lock();
|
||||
if self.flags.contains(NodeFlags::IN_MEMORY_PROPS) {
|
||||
let mut cache = self.props.lock();
|
||||
|
||||
let metadata = cache
|
||||
.metadata
|
||||
.get_or_try_insert_with(|| self.data_as_common().metadata(self))?;
|
||||
let metadata = cache
|
||||
.metadata
|
||||
.get_or_try_insert_with(|| self.data_as_common().metadata(self))?;
|
||||
|
||||
Ok(*metadata)
|
||||
Ok(*metadata)
|
||||
} else {
|
||||
self.data_as_common().metadata(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_metadata(self: &NodeRef, update: &FileMetadataUpdate) -> Result<(), Error> {
|
||||
let FileMetadataUpdate::Permissions(mode) = update else {
|
||||
return Err(Error::NotImplemented);
|
||||
};
|
||||
|
||||
let mut cache = self.props.lock();
|
||||
let common = self.data_as_common();
|
||||
|
||||
let metadata = cache
|
||||
.metadata
|
||||
.get_or_try_insert_with(|| common.metadata(self))?;
|
||||
if self.flags.contains(NodeFlags::IN_MEMORY_PROPS) {
|
||||
let mut cache = self.props.lock();
|
||||
|
||||
match *mode {
|
||||
FileMetadataUpdateMode::Set(value) => metadata.mode |= value,
|
||||
FileMetadataUpdateMode::Modify { set, clear } => {
|
||||
metadata.mode &= !clear;
|
||||
metadata.mode |= set;
|
||||
}
|
||||
}
|
||||
|
||||
if !self.flags.contains(NodeFlags::IN_MEMORY_PROPS) {
|
||||
let metadata = cache
|
||||
.metadata
|
||||
.get_or_try_insert_with(|| common.metadata(self))?;
|
||||
metadata.update(update);
|
||||
Ok(())
|
||||
} else {
|
||||
let mut metadata = common.metadata(self)?;
|
||||
metadata.update(update);
|
||||
// Update permissions in the real node
|
||||
common.set_metadata(self, metadata)?;
|
||||
common.set_metadata(self, &metadata)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO clarify directory size
|
||||
|
@ -273,7 +273,7 @@ pub(crate) fn get_metadata(
|
||||
let metadata = node.metadata()?;
|
||||
let size = node.size()?;
|
||||
|
||||
buffer.write(FileAttr {
|
||||
let metadata = FileAttr {
|
||||
size,
|
||||
ty: node.ty(),
|
||||
mode: metadata.mode,
|
||||
@ -284,9 +284,9 @@ pub(crate) fn get_metadata(
|
||||
block_size: metadata.block_size,
|
||||
ctime: metadata.ctime,
|
||||
mtime: metadata.mtime,
|
||||
// TODO atime?
|
||||
atime: metadata.mtime,
|
||||
});
|
||||
};
|
||||
buffer.write(metadata);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
|
@ -103,11 +103,11 @@ struct FileAttr {
|
||||
pub gid: GroupId,
|
||||
|
||||
/// Creation time
|
||||
pub ctime: u64,
|
||||
pub ctime: SystemTime,
|
||||
/// Last modification time
|
||||
pub mtime: u64,
|
||||
pub mtime: SystemTime,
|
||||
/// Last access time
|
||||
pub atime: u64,
|
||||
pub atime: SystemTime,
|
||||
}
|
||||
|
||||
/// Raw directory entry representation
|
||||
|
@ -26,7 +26,7 @@ pub use abi_serde;
|
||||
mod generated {
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use crate::{arch::SavedFrame, process::SpawnOption, util::FixedString};
|
||||
use crate::{arch::SavedFrame, process::SpawnOption, time::SystemTime, util::FixedString};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/generated_types.rs"));
|
||||
}
|
||||
|
@ -60,17 +60,21 @@ fn terminate_by_signal(signal: Signal) -> ! {
|
||||
}
|
||||
|
||||
/// Updates the handler for a particular signal. Returns the old handler used for that signal.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Marked as unsafe due to being thread-unsafe. Will be lifted once I port RwLock into the runtime
|
||||
/// crate.
|
||||
pub unsafe fn set_handler(signal: Signal, handler: SignalHandler) -> SignalHandler {
|
||||
pub fn set_handler(signal: Signal, handler: SignalHandler) -> SignalHandler {
|
||||
let mut table = TABLE.write();
|
||||
let entry = &mut table[signal.into_raw() as usize];
|
||||
core::mem::replace(entry, handler)
|
||||
}
|
||||
|
||||
/// Updates all signal handlers to point to a single handler. Intended to be used with custom
|
||||
/// signal "routers".
|
||||
pub fn set_all_handlers(handler: SignalHandler) {
|
||||
let mut table = TABLE.write();
|
||||
for entry in table.iter_mut() {
|
||||
*entry = handler;
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the stack that will be used to handle signals **on this thread**.
|
||||
///
|
||||
/// # Safety
|
||||
|
4
ports/c-tests/compile.sh
Executable file
4
ports/c-tests/compile.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
mkdir -p $3
|
||||
clang -target $Y_TRIPLE --sysroot $Y_SYSROOT -fPIC -o $3/c-test $1/test.c
|
4
ports/c-tests/install.sh
Executable file
4
ports/c-tests/install.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
mkdir -p $Y_SYSROOT/bin
|
||||
install -m0755 $3/c-test $Y_SYSROOT/bin/c-test
|
@ -2,4 +2,4 @@ description = "Test C/C++ programs"
|
||||
version = "0.0.1"
|
||||
|
||||
[dependencies]
|
||||
runtime = ["meta-libc", "libc++"]
|
||||
runtime = ["meta-libc", "compiler-rt"]
|
||||
|
15
ports/c-tests/test.c
Normal file
15
ports/c-tests/test.c
Normal file
@ -0,0 +1,15 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
struct stat s;
|
||||
if (stat("/etc/test.c", &s) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("t = %lds, %ldns\n", s.st_mtim.tv_sec, s.st_mtim.tv_nsec);
|
||||
|
||||
return 0;
|
||||
}
|
@ -2,5 +2,11 @@
|
||||
|
||||
build_dir=$3
|
||||
|
||||
RT_LIB_DIR=$Y_SYSROOT/lib/clang/19/lib/$Y_TRIPLE
|
||||
|
||||
cd $build_dir
|
||||
cmake --build . -t install -j >/dev/null
|
||||
|
||||
mkdir -p $RT_LIB_DIR
|
||||
cd $RT_LIB_DIR
|
||||
ln -sf ../../../../yggdrasil/libclang_rt.builtins-$Y_ARCH.a libclang_rt.builtins.a
|
||||
|
@ -5,3 +5,7 @@ set -e
|
||||
build_dir=$3
|
||||
cd $build_dir
|
||||
cmake --build . -t install -j >/dev/null
|
||||
|
||||
ln -sf clang $Y_SYSROOT/bin/cc
|
||||
ln -sf clang++ $Y_SYSROOT/bin/cxx
|
||||
ln -sf lld $Y_SYSROOT/bin/ld
|
||||
|
1
userspace/.gitignore
vendored
1
userspace/.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
/target
|
||||
/dynload-program/target
|
||||
/etc/rc.d/*.ext
|
||||
|
@ -79,14 +79,19 @@ pub fn build_argument(args: &[String], auxv: &[AuxValue]) -> Result<usize, Error
|
||||
let mut placer = ArgPlacer::new(&mut buffer[..]);
|
||||
|
||||
let mut argv = vec![];
|
||||
let mut envp = vec![];
|
||||
|
||||
for arg in args {
|
||||
argv.push(placer.put_str(arg)? + arg_base);
|
||||
}
|
||||
for (key, value) in std::env::vars() {
|
||||
let env_string = format!("{key}={value}");
|
||||
envp.push(placer.put_str(&env_string)? + arg_base);
|
||||
}
|
||||
|
||||
// TODO env
|
||||
let argv = placer.put_ptr_array(&argv)? + arg_base;
|
||||
let envp = placer.put_ptr_array(&[])? + arg_base;
|
||||
let envp = placer.put_ptr_array(&envp)? + arg_base;
|
||||
let auxv = placer.put_aux_array(auxv)? + arg_base;
|
||||
|
||||
let argument = placer.position + arg_base;
|
||||
|
@ -1,6 +0,0 @@
|
||||
.section .text
|
||||
.global _start
|
||||
_start:
|
||||
mov $12, %rax
|
||||
mov $123, %rdi
|
||||
syscall
|
@ -1,10 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
printf("Argument count: %d\n", argc);
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
printf("Argument %d is %s\n", i, argv[i]);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
std::cout << "Test!!!" << std::endl;
|
||||
return 0;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
1. List item one.
|
||||
|
||||
List item one continued with a second paragraph followed by an
|
||||
Indented block.
|
||||
|
||||
$ ls *.sh
|
||||
$ mv *.sh ~/tmp
|
||||
|
||||
List item continued with a third paragraph.
|
||||
|
||||
2. List item two continued with an open block.
|
||||
|
||||
This paragraph is part of the preceding list item.
|
||||
|
||||
1. This list is nested and does not require explicit item continuation.
|
||||
|
||||
This paragraph is part of the preceding list item.
|
||||
|
||||
2. List item b.
|
||||
|
||||
This paragraph belongs to item two of the outer list.
|
||||
|
||||
> This is a blockquote
|
||||
>> This is a quote of a quote
|
||||
>> * This is an item of quote-quote list
|
||||
>>
|
||||
>> This is a continuation of quote-quote-list
|
||||
>> * This is another item of a quote-quote list
|
||||
|
||||
Another paragraph
|
||||
|
||||
* Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eget congue risus. Aenean facilisis quis augue ac accumsan. Praesent felis odio, sagittis ut pulvinar a, pharetra non ante. Cras accumsan varius auctor. Suspendisse pharetra mauris eget eros congue, ut scelerisque enim pharetra. Quisque pellentesque ante quis porttitor condimentum. Nullam nisi purus, interdum a dui vitae, hendrerit eleifend leo. Integer tempus neque ut neque faucibus vulputate. Ut orci tellus, interdum et sagittis eu, interdum ut ex. Donec ac consectetur sem. Aenean eget mauris rutrum, condimentum nisi nec, tempor nulla. Nullam ullamcorper nibh vel ligula pellentesque blandit. Curabitur suscipit placerat gravida. Nam id consectetur urna. Morbi viverra lorem vel nulla varius, at placerat nulla posuere. Donec in bibendum ex, ut tincidunt sapien.
|
||||
* In ut quam tellus. Nunc ac sem vestibulum, sollicitudin ligula id, facilisis tortor. Pellentesque quam ex, ornare id diam ac, sagittis volutpat quam. Etiam faucibus, eros non tristique venenatis, odio risus interdum dolor, porttitor volutpat nulla erat in ex. Nullam venenatis leo justo. Integer ullamcorper auctor orci, non pulvinar nisi volutpat molestie. Phasellus tristique, leo id convallis cursus, diam dolor pretium dui, nec suscipit nisl ligula sit amet magna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Maecenas sit amet nibh vel mauris sagittis semper quis efficitur mauris. Aenean iaculis, lectus sit amet placerat scelerisque, dui libero maximus orci, at convallis justo urna eget quam. Aenean luctus felis tristique enim suscipit, non porta eros gravida. Aliquam erat volutpat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum eleifend iaculis fringilla.
|
||||
* Fusce eleifend mauris vel urna pretium, non suscipit massa accumsan. Phasellus pretium ultricies accumsan. Suspendisse accumsan bibendum erat, sit amet eleifend ipsum maximus in. Curabitur eleifend, ipsum ut sollicitudin varius, felis lectus elementum nibh, eget bibendum mi ex eget lacus. Nam erat sapien, sodales nec bibendum cursus, accumsan eget magna. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut quis aliquam est. Nunc et erat lacus. Proin consequat eleifend fringilla. Phasellus eget nulla orci. Proin fermentum mi eu nisi posuere blandit. Interdum et malesuada fames ac ante ipsum primis in faucibus.
|
||||
* In eget facilisis nisi. Donec purus dolor, fringilla nec efficitur nec, elementum id metus. Aenean a scelerisque augue. Nullam tempor porttitor eros tempus imperdiet. Sed euismod felis sed neque venenatis, quis lobortis odio sagittis. Phasellus tristique auctor massa eget vulputate. Etiam nulla tellus, congue ut euismod a, posuere quis sapien. Morbi pellentesque orci sit amet commodo interdum. Nunc eleifend, velit consectetur tempor dictum, sem turpis rutrum erat, eget vehicula justo felis id erat. Morbi condimentum pulvinar sem, sit amet molestie enim suscipit quis. Aliquam convallis ante lectus, at lacinia ex gravida semper. Morbi vel metus aliquam, vulputate neque ac, sodales arcu. Ut quis bibendum sem.
|
||||
* Vivamus elementum augue eget ligula laoreet, et feugiat turpis efficitur. Mauris eleifend lacus id felis condimentum, vitae volutpat tellus volutpat. Vestibulum justo diam, bibendum sit amet neque quis, commodo luctus nunc. Donec luctus, libero vel viverra venenatis, nisl libero cursus massa, dapibus tempus libero erat facilisis lacus. Donec vitae finibus metus, porta tempor velit. Proin velit odio, facilisis sit amet elementum at, laoreet at tellus. Phasellus convallis, neque sit amet imperdiet hendrerit, nisi quam laoreet odio, molestie venenatis nisl ligula in erat.
|
@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
/sbin/mount -t ext2 /dev/vb0p1 /mnt
|
||||
/mnt/bin/clang -cc1as -filetype obj -main-file-name test.S -target-cpu x86-64 -mrelocation-model pic -triple x86_64-unknown-yggdrasil -o /test.o /etc/test.S
|
||||
/mnt/bin/ld.lld -nostdlib -o /test /test.o
|
||||
/bin/ls -lh /
|
||||
|
@ -147,7 +147,13 @@ unsafe extern "C" fn fcntl(fd: c_int, cmd: c_int, _args: ...) -> CIntCountResult
|
||||
// TODO kernel support for fcntl
|
||||
let _file = RawFile::e_try_from(fd)?;
|
||||
|
||||
todo!("fcntl({}, {}, ...)", fd, cmd);
|
||||
match cmd {
|
||||
F_GETFD => CIntCountResult::success(0),
|
||||
F_SETFD => CIntCountResult::success(0),
|
||||
_ => {
|
||||
todo!("fcntl({}, {}, ...)", fd, cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn vopenat(atfd: c_int, pathname: *const c_char, opts: c_int, mut ap: VaList) -> CFdResult {
|
||||
|
@ -94,7 +94,7 @@ unsafe extern "C" fn newlocale(
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn setlocale(_category: c_int, _locale: *const c_char) -> *mut c_char {
|
||||
// TODO
|
||||
todo!()
|
||||
c"C".as_ptr().cast_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -43,7 +43,8 @@ unsafe extern "C" fn pthread_create(
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_detach(_thread: pthread_t) -> c_int {
|
||||
todo!()
|
||||
// TODO
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -1,12 +1,12 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_int, c_long, c_void},
|
||||
ffi::{c_char, c_int, c_long, c_void, CStr},
|
||||
ptr::NonNull,
|
||||
};
|
||||
|
||||
use yggdrasil_rt::process::{signal as rt, Signal};
|
||||
|
||||
use crate::{
|
||||
error::{self, CIntZeroResult, CResult, EResult, TryFromExt},
|
||||
error::{self, CIntZeroResult, CResult, EResult},
|
||||
headers::errno::Errno,
|
||||
signal,
|
||||
util::PointerExt,
|
||||
@ -17,7 +17,7 @@ use super::{
|
||||
sys_types::{pid_t, uid_t},
|
||||
};
|
||||
|
||||
pub type sig_handler_t = unsafe extern "C" fn(SigNumber);
|
||||
pub type sig_handler_t = unsafe extern "C" fn(c_int);
|
||||
|
||||
pub type sigset_t = u64;
|
||||
|
||||
@ -72,45 +72,41 @@ pub union sigval {
|
||||
// SIG_DFL, SIG_ERR, SIG_HOLD, SIG_IGN are in <bits/signal.h>
|
||||
|
||||
extern "C" {
|
||||
fn __sig_terminate(_: SigNumber);
|
||||
fn __sig_ignore(_: SigNumber);
|
||||
fn __sig_terminate(_: c_int);
|
||||
fn __sig_ignore(_: c_int);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
#[repr(C)]
|
||||
pub enum SigNumber {
|
||||
SIGHUP = 1,
|
||||
SIGINT = 2,
|
||||
SIGQUIT = 3,
|
||||
SIGILL = 4,
|
||||
SIGTRAP = 5,
|
||||
SIGABRT = 6,
|
||||
SIGBUS = 7,
|
||||
SIGFPE = 8,
|
||||
SIGKILL = 9,
|
||||
SIGUSR1 = 10,
|
||||
SIGSEGV = 11,
|
||||
SIGUSR2 = 12,
|
||||
SIGPIPE = 13,
|
||||
SIGALRM = 14,
|
||||
SIGTERM = 15,
|
||||
SIGCHLD = 17,
|
||||
SIGCONT = 18,
|
||||
SIGSTOP = 19,
|
||||
SIGTSTP = 20,
|
||||
SIGTTIN = 21,
|
||||
SIGTTOU = 22,
|
||||
SIGURG = 23,
|
||||
SIGXCPU = 24,
|
||||
SIGXFSZ = 25,
|
||||
SIGVTALRM = 26,
|
||||
SIGPROF = 27,
|
||||
SIGWINCH = 28,
|
||||
SIGPOLL = 29,
|
||||
SIGPWR = 30,
|
||||
SIGSYS = 31,
|
||||
}
|
||||
pub const SIGHUP: c_int = 1;
|
||||
pub const SIGINT: c_int = 2;
|
||||
pub const SIGQUIT: c_int = 3;
|
||||
pub const SIGILL: c_int = 4;
|
||||
pub const SIGTRAP: c_int = 5;
|
||||
pub const SIGABRT: c_int = 6;
|
||||
pub const SIGBUS: c_int = 7;
|
||||
pub const SIGFPE: c_int = 8;
|
||||
pub const SIGKILL: c_int = 9;
|
||||
pub const SIGUSR1: c_int = 10;
|
||||
pub const SIGSEGV: c_int = 11;
|
||||
pub const SIGUSR2: c_int = 12;
|
||||
pub const SIGPIPE: c_int = 13;
|
||||
pub const SIGALRM: c_int = 14;
|
||||
pub const SIGTERM: c_int = 15;
|
||||
pub const SIGCHLD: c_int = 17;
|
||||
pub const SIGCONT: c_int = 18;
|
||||
pub const SIGSTOP: c_int = 19;
|
||||
pub const SIGTSTP: c_int = 20;
|
||||
pub const SIGTTIN: c_int = 21;
|
||||
pub const SIGTTOU: c_int = 22;
|
||||
pub const SIGURG: c_int = 23;
|
||||
pub const SIGXCPU: c_int = 24;
|
||||
pub const SIGXFSZ: c_int = 25;
|
||||
pub const SIGVTALRM: c_int = 26;
|
||||
pub const SIGPROF: c_int = 27;
|
||||
pub const SIGWINCH: c_int = 28;
|
||||
pub const SIGPOLL: c_int = 29;
|
||||
pub const SIGPWR: c_int = 30;
|
||||
pub const SIGSYS: c_int = 31;
|
||||
pub const SIGNAL_MAX: c_int = SIGSYS + 1;
|
||||
|
||||
pub const SIGEV_NONE: c_int = 0;
|
||||
pub const SIGEV_SIGNAL: c_int = 1;
|
||||
@ -134,32 +130,64 @@ pub const SS_DISABLE: c_int = 1 << 9;
|
||||
pub const MINSIGSTKSZ: usize = 2 * 4096;
|
||||
pub const SIGSTKSZ: usize = 8 * 4096;
|
||||
|
||||
impl TryFromExt<SigNumber> for Signal {
|
||||
fn e_try_from(value: SigNumber) -> EResult<Self> {
|
||||
match value {
|
||||
SigNumber::SIGABRT => EResult::Ok(Signal::Aborted),
|
||||
SigNumber::SIGSEGV => EResult::Ok(Signal::MemoryAccessViolation),
|
||||
SigNumber::SIGINT => EResult::Ok(Signal::Interrupted),
|
||||
SigNumber::SIGILL => EResult::Ok(Signal::InvalidInstruction),
|
||||
SigNumber::SIGKILL => EResult::Ok(Signal::Killed),
|
||||
SigNumber::SIGTERM => EResult::Ok(Signal::Terminated),
|
||||
_ => EResult::Err(Errno::EINVAL),
|
||||
}
|
||||
pub fn int_to_signum(value: c_int) -> EResult<Signal> {
|
||||
match value {
|
||||
SIGABRT => EResult::Ok(Signal::Aborted),
|
||||
SIGSEGV => EResult::Ok(Signal::MemoryAccessViolation),
|
||||
SIGINT => EResult::Ok(Signal::Interrupted),
|
||||
SIGILL => EResult::Ok(Signal::InvalidInstruction),
|
||||
SIGKILL => EResult::Ok(Signal::Killed),
|
||||
SIGTERM => EResult::Ok(Signal::Terminated),
|
||||
_ => EResult::Err(Errno::EINVAL),
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Signal> for SigNumber {
|
||||
fn from(value: Signal) -> Self {
|
||||
match value {
|
||||
Signal::Aborted => Self::SIGABRT,
|
||||
Signal::MemoryAccessViolation => Self::SIGSEGV,
|
||||
Signal::Interrupted => Self::SIGINT,
|
||||
Signal::InvalidInstruction => Self::SIGILL,
|
||||
Signal::Killed => Self::SIGKILL,
|
||||
Signal::Terminated => Self::SIGTERM,
|
||||
// Never issued/handled
|
||||
Signal::Debug => unreachable!(),
|
||||
}
|
||||
pub fn signum_to_int(value: Signal) -> c_int {
|
||||
match value {
|
||||
Signal::Aborted => SIGABRT,
|
||||
Signal::MemoryAccessViolation => SIGSEGV,
|
||||
Signal::Interrupted => SIGINT,
|
||||
Signal::InvalidInstruction => SIGILL,
|
||||
Signal::Killed => SIGKILL,
|
||||
Signal::Terminated => SIGTERM,
|
||||
// Never issued/handled
|
||||
Signal::Debug => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signal_string(value: c_int) -> Option<&'static CStr> {
|
||||
match value {
|
||||
SIGHUP => Some(c"Hangup"),
|
||||
SIGINT => Some(c"Interrupted"),
|
||||
SIGQUIT => Some(c"Quit"),
|
||||
SIGILL => Some(c"Illegal instruction"),
|
||||
SIGTRAP => Some(c"Trap/breakpoint"),
|
||||
SIGABRT => Some(c"Aborted"),
|
||||
SIGBUS => Some(c"Bus error"),
|
||||
SIGFPE => Some(c"Floating-point exception"),
|
||||
SIGKILL => Some(c"Killed"),
|
||||
SIGUSR1 => Some(c"User signal 1"),
|
||||
SIGSEGV => Some(c"Segmentation fault"),
|
||||
SIGUSR2 => Some(c"User signal 2"),
|
||||
SIGPIPE => Some(c"Broken pipe"),
|
||||
SIGALRM => Some(c"Timer alarm"),
|
||||
SIGTERM => Some(c"Terminated"),
|
||||
SIGCHLD => Some(c"Child quit"),
|
||||
SIGCONT => Some(c"Continued"),
|
||||
SIGSTOP => Some(c"Stopped"),
|
||||
SIGTSTP => Some(c"Terminal stopped"),
|
||||
SIGTTIN => Some(c"Background process terminal input"),
|
||||
SIGTTOU => Some(c"Background process terminal output"),
|
||||
SIGURG => Some(c"Urgent"),
|
||||
SIGXCPU => Some(c"CPU time limit exceeded"),
|
||||
SIGXFSZ => Some(c"File size limit exceeded"),
|
||||
SIGVTALRM => Some(c"Virtual alarm"),
|
||||
SIGPROF => Some(c"Profiling timer expired"),
|
||||
SIGWINCH => Some(c"Window size changed"),
|
||||
SIGPOLL => Some(c"Pollable event"),
|
||||
SIGPWR => Some(c"Power failure"),
|
||||
SIGSYS => Some(c"Bad system call"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,7 +233,7 @@ unsafe extern "C" fn raise(_signum: c_int) -> c_int {
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn sigaction(
|
||||
signum: SigNumber,
|
||||
signum: c_int,
|
||||
_new: *const sigaction,
|
||||
_old: *mut sigaction,
|
||||
) -> CIntZeroResult {
|
||||
@ -214,8 +242,13 @@ unsafe extern "C" fn sigaction(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn sigaddset(_mask: *mut sigset_t, _signum: c_int) -> c_int {
|
||||
todo!()
|
||||
unsafe extern "C" fn sigaddset(mask: *mut sigset_t, signum: c_int) -> CIntZeroResult {
|
||||
if signum > 63 || signum <= 0 {
|
||||
error::errno = Errno::EINVAL;
|
||||
return CIntZeroResult::ERROR;
|
||||
}
|
||||
*mask |= 1 << signum;
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -277,7 +310,7 @@ unsafe extern "C" fn sigismember(_mask: *const sigset_t, _signum: c_int) -> c_in
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn signal(handler: sig_handler_t, signum: SigNumber) -> sig_handler_t {
|
||||
unsafe extern "C" fn signal(signum: c_int, handler: sig_handler_t) -> sig_handler_t {
|
||||
// Validate handler
|
||||
let address = handler as usize;
|
||||
// NULL or SIG_ERR
|
||||
|
@ -37,20 +37,24 @@ unsafe extern "C" fn posix_spawn(
|
||||
_file_actions: *const posix_spawn_file_actions_t,
|
||||
_attrp: *const posix_spawnattr_t,
|
||||
argv: *const *mut c_char,
|
||||
_envp: *const *mut c_char,
|
||||
envp: *const *mut c_char,
|
||||
) -> CIntZeroResult {
|
||||
let path = path.ensure_str();
|
||||
let argv = NullTerminatedArrayIter::new(argv);
|
||||
let envp = NullTerminatedArrayIter::new(envp);
|
||||
let args = argv
|
||||
.map(|arg| arg.cast_const().ensure_str())
|
||||
.collect::<Vec<_>>();
|
||||
let envs = envp
|
||||
.map(|env| env.cast_const().ensure_str())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
log::info!("posix_spawn({path:?}, {args:?})");
|
||||
log::info!("posix_spawn({path:?}, {args:?}, {envs:?})");
|
||||
|
||||
let options = SpawnOptions {
|
||||
program: path,
|
||||
arguments: &args,
|
||||
environment: &[],
|
||||
environment: &envs,
|
||||
directory: None,
|
||||
optional: &[
|
||||
SpawnOption::CopyFile {
|
||||
@ -72,6 +76,7 @@ unsafe extern "C" fn posix_spawn(
|
||||
if let Some(pid) = pid.as_mut() {
|
||||
*pid = id.bits() as i32;
|
||||
}
|
||||
log::info!(" -> {id:?}");
|
||||
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
@ -120,19 +125,23 @@ unsafe extern "C" fn posix_spawn_file_actions_addopen(
|
||||
unsafe extern "C" fn posix_spawn_file_actions_destroy(
|
||||
_file_actions: *mut posix_spawn_file_actions_t,
|
||||
) -> c_int {
|
||||
todo!()
|
||||
log::warn!("TODO: posix_spawn_file_actions_destroy");
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn posix_spawn_file_actions_init(
|
||||
_file_actions: *mut posix_spawn_file_actions_t,
|
||||
) -> c_int {
|
||||
todo!()
|
||||
log::warn!("TODO: posix_spawn_file_actions_init");
|
||||
0
|
||||
// todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn posix_spawnattr_destroy(_attrp: *mut posix_spawnattr_t) -> c_int {
|
||||
todo!()
|
||||
log::warn!("TODO: posix_spawnattr_destroy");
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -186,7 +195,8 @@ unsafe extern "C" fn posix_spawnattr_getsigmask(
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn posix_spawnattr_init(_attrp: *mut posix_spawnattr_t) -> c_int {
|
||||
todo!()
|
||||
log::warn!("TODO: posix_spawnattr_init");
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -194,7 +204,8 @@ unsafe extern "C" fn posix_spawnattr_setflags(
|
||||
_attrp: *mut posix_spawnattr_t,
|
||||
_flags: c_short,
|
||||
) -> c_int {
|
||||
todo!()
|
||||
log::warn!("TODO: posix_spawnattr_setflags");
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -234,5 +245,7 @@ unsafe extern "C" fn posix_spawnattr_setsigmask(
|
||||
_attrp: *mut posix_spawnattr_t,
|
||||
_sigset: *const c_void,
|
||||
) -> c_int {
|
||||
todo!()
|
||||
log::warn!("TODO: posix_spawnattr_setsigmask");
|
||||
0
|
||||
// todo!()
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use core::{
|
||||
use crate::{
|
||||
allocator,
|
||||
error::CPtrResult,
|
||||
headers::{errno::Errno, locale::locale_t},
|
||||
headers::{errno::Errno, locale::locale_t, signal::signal_string},
|
||||
};
|
||||
|
||||
use super::mem::{memcpy, mempcpy, memset};
|
||||
@ -69,7 +69,15 @@ unsafe extern "C" fn strcmp(a: *const c_char, b: *const c_char) -> c_int {
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char {
|
||||
stpcpy(dst, src);
|
||||
let mut i = 0;
|
||||
loop {
|
||||
let c = src.add(i).read();
|
||||
dst.add(i).write(c);
|
||||
if c == 0 {
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
dst
|
||||
}
|
||||
|
||||
@ -246,8 +254,11 @@ unsafe extern "C" fn strrchr(a: *const c_char, c: c_int) -> *mut c_char {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn strsignal(_signum: c_int) -> *mut c_char {
|
||||
todo!()
|
||||
unsafe extern "C" fn strsignal(signum: c_int) -> *mut c_char {
|
||||
match signal_string(signum) {
|
||||
Some(name) => name.as_ptr().cast_mut(),
|
||||
None => null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -13,7 +13,7 @@ use crate::{
|
||||
|
||||
use super::{
|
||||
fcntl::{AT_FDCWD, AT_SYMLINK_NOFOLLOW},
|
||||
sys_time::__ygg_timespec_t,
|
||||
sys_time::{__ygg_timespec_t, timespec},
|
||||
sys_types::{blkcnt_t, blksize_t, dev_t, gid_t, ino_t, mode_t, nlink_t, off_t, uid_t},
|
||||
};
|
||||
|
||||
@ -77,10 +77,13 @@ impl From<FileAttr> for stat {
|
||||
let st_size: off_t = value.size.try_into().unwrap();
|
||||
let st_uid = u32::from(value.uid).try_into().unwrap();
|
||||
let st_gid = u32::from(value.gid).try_into().unwrap();
|
||||
// TODO
|
||||
let st_blksize = value.block_size as _;
|
||||
let st_blocks = st_size.div_ceil(st_blksize as _).try_into().unwrap();
|
||||
let st_ino = value.inode.unwrap_or(0) as u64;
|
||||
let st_ctim = timespec::from(value.ctime);
|
||||
let st_mtim = timespec::from(value.mtime);
|
||||
let st_atim = timespec::from(value.atime);
|
||||
log::info!("{st_mtim:?}, {:?}", value.mtime);
|
||||
|
||||
Self {
|
||||
st_mode,
|
||||
@ -90,7 +93,12 @@ impl From<FileAttr> for stat {
|
||||
st_blksize,
|
||||
st_blocks,
|
||||
st_ino,
|
||||
..Default::default()
|
||||
st_mtim,
|
||||
st_atim,
|
||||
st_ctim,
|
||||
st_nlink: 1,
|
||||
st_dev: 0,
|
||||
st_rdev: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ use core::{
|
||||
};
|
||||
|
||||
use yggdrasil_abi::time::MICROSECONDS_IN_SECOND;
|
||||
use yggdrasil_rt::time::SystemTime;
|
||||
|
||||
use super::sys_types::{suseconds_t, time_t};
|
||||
|
||||
@ -97,6 +98,15 @@ impl From<__ygg_timespec_t> for Duration {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SystemTime> for __ygg_timespec_t {
|
||||
fn from(value: SystemTime) -> Self {
|
||||
Self {
|
||||
tv_sec: time_t(value.seconds() as i64),
|
||||
tv_nsec: value.subsec_nanos() as i64,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Duration> for __ygg_timespec_t {
|
||||
fn from(value: Duration) -> Self {
|
||||
Self {
|
||||
|
@ -39,7 +39,9 @@ fn wait_inner(what: ProcessWait, nonblocking: bool) -> EResult<WaitResult> {
|
||||
if nonblocking {
|
||||
flags |= WaitFlags::NON_BLOCKING;
|
||||
}
|
||||
log::info!("wait_inner({what:?})");
|
||||
let pid = unsafe { syscall::wait_process(&what, &mut status, flags) }.e_map_err(Errno::from)?;
|
||||
log::info!(" -> {pid:?}");
|
||||
|
||||
EResult::Ok(WaitResult { pid, status })
|
||||
}
|
||||
@ -68,8 +70,20 @@ fn encode_exit_status(code: ExitCode) -> c_int {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn wait(_status: *mut c_int) -> pid_t {
|
||||
todo!()
|
||||
unsafe extern "C" fn wait(status: *mut c_int) -> pid_t {
|
||||
let result = wait_inner(ProcessWait::AnyChild, false);
|
||||
match result {
|
||||
EResult::Ok(res) => {
|
||||
if let Some(status) = status.as_mut() {
|
||||
*status = encode_exit_status(res.status);
|
||||
}
|
||||
res.pid.bits() as pid_t
|
||||
}
|
||||
EResult::Err(error) => {
|
||||
error::errno = error;
|
||||
-1 as pid_t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO siginfo_t
|
||||
|
@ -1,13 +1,17 @@
|
||||
use core::ffi::{c_char, c_int, c_long};
|
||||
use core::{
|
||||
ffi::{c_char, c_int, c_long},
|
||||
ptr::{null_mut, NonNull},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::{CIntZeroResult, TryFromExt},
|
||||
error::{self, CIntZeroResult, CPtrResult, EResult, TryFromExt},
|
||||
headers::{
|
||||
errno::Errno,
|
||||
fcntl::{faccessat, AT_FDCWD},
|
||||
sys_types::{gid_t, off_t, uid_t},
|
||||
},
|
||||
io::{raw::RawFile, FromRawFd},
|
||||
util::PointerExt,
|
||||
io::{self, raw::RawFile, FromRawFd},
|
||||
util::{PointerExt, PointerStrExt},
|
||||
};
|
||||
|
||||
pub const _PC_PATH_MAX: c_int = 0;
|
||||
@ -18,8 +22,10 @@ unsafe extern "C" fn access(path: *const c_char, mode: c_int) -> CIntZeroResult
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn chdir(path: *const c_char) -> c_int {
|
||||
todo!()
|
||||
unsafe extern "C" fn chdir(path: *const c_char) -> CIntZeroResult {
|
||||
let path = path.ensure_str();
|
||||
io::set_current_directory(None, path)?;
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -56,17 +62,21 @@ unsafe extern "C" fn ftruncate(fd: c_int, size: off_t) -> CIntZeroResult {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn getcwd(buf: *mut c_char, len: usize) -> *mut c_char {
|
||||
let buffer = buf.ensure_slice_mut(len);
|
||||
// TODO
|
||||
if buffer.len() < 2 {
|
||||
return core::ptr::null_mut();
|
||||
}
|
||||
unsafe extern "C" fn getcwd(buf: *mut c_char, len: usize) -> CPtrResult<c_char> {
|
||||
let result = io::get_current_directory(|s| {
|
||||
if buf.is_null() {
|
||||
todo!();
|
||||
}
|
||||
if len < s.len() + 1 {
|
||||
return EResult::Err(Errno::ERANGE);
|
||||
}
|
||||
let buffer = buf.cast::<u8>().ensure_slice_mut(len);
|
||||
buffer[..s.len()].copy_from_slice(s.as_bytes());
|
||||
buffer[s.len()] = 0;
|
||||
EResult::Ok(NonNull::new_unchecked(buf))
|
||||
})?;
|
||||
|
||||
buffer[0] = b'/' as _;
|
||||
buffer[1] = 0;
|
||||
|
||||
buffer.as_mut_ptr()
|
||||
CPtrResult::success(result)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -126,7 +136,9 @@ unsafe extern "C" fn truncate(path: *const c_char, size: off_t) -> c_int {
|
||||
}
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn unlink(path: *const c_char) -> c_int {
|
||||
todo!()
|
||||
let path = path.ensure_str();
|
||||
log::warn!("TODO: unlink({path:?})");
|
||||
0
|
||||
}
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn unlinkat(atfd: c_int, path: *const c_char, flags: c_int) -> c_int {
|
||||
|
@ -1,4 +1,11 @@
|
||||
use core::ffi::{c_char, c_int, c_long, c_uint, c_void};
|
||||
use core::ffi::{c_char, c_int, c_long, c_uint, c_void, CStr};
|
||||
|
||||
use crate::{
|
||||
env::get_env,
|
||||
error::{self, EResult},
|
||||
headers::errno::Errno,
|
||||
util::PointerExt,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
#[non_exhaustive]
|
||||
@ -12,6 +19,8 @@ pub enum Sysconf {
|
||||
_SC_ARG_MAX,
|
||||
}
|
||||
|
||||
pub const _CS_PATH: c_int = 1;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn alarm(value: c_uint) -> c_uint {
|
||||
todo!()
|
||||
@ -19,7 +28,33 @@ unsafe extern "C" fn alarm(value: c_uint) -> c_uint {
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn confstr(name: c_int, buf: *mut c_char, size: usize) -> usize {
|
||||
todo!()
|
||||
match name {
|
||||
_CS_PATH => {
|
||||
let path = match get_env("PATH".as_bytes()) {
|
||||
EResult::Ok(value) => value,
|
||||
EResult::Err(err) => {
|
||||
error::errno = Errno::EINVAL;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
let Some(path) = path else {
|
||||
return 0;
|
||||
};
|
||||
let cstr = CStr::from_ptr(path.as_ptr());
|
||||
if !buf.is_null() && size > 0 {
|
||||
let buf = buf.cast::<u8>().ensure_slice_mut(size);
|
||||
let bytes = cstr.to_bytes();
|
||||
let len = core::cmp::min(buf.len() - 1, bytes.len());
|
||||
buf[..len].copy_from_slice(&bytes[..len]);
|
||||
buf[len] = 0;
|
||||
}
|
||||
cstr.to_bytes().len()
|
||||
}
|
||||
_ => {
|
||||
error::errno = Errno::EINVAL;
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -136,6 +136,18 @@ pub fn create_directory(at: Option<RawFd>, path: &str, mode: FileMode) -> EResul
|
||||
EResult::Ok(())
|
||||
}
|
||||
|
||||
pub fn set_current_directory(at: Option<RawFd>, path: &str) -> EResult<()> {
|
||||
// TODO
|
||||
assert!(at.is_none());
|
||||
yggdrasil_rt::io::set_current_directory(path)?;
|
||||
EResult::Ok(())
|
||||
}
|
||||
|
||||
pub fn get_current_directory<T, F: FnOnce(&str) -> EResult<T>>(mapper: F) -> EResult<T> {
|
||||
let result = yggdrasil_rt::io::current_directory(mapper)??;
|
||||
EResult::Ok(result)
|
||||
}
|
||||
|
||||
pub fn realpath<P: AsRef<Path>>(path: P) -> EResult<PathBuf> {
|
||||
// Cases:
|
||||
// * /a/b/c -> /a/b/c
|
||||
|
@ -1,29 +1,54 @@
|
||||
use yggdrasil_rt::process::{
|
||||
signal::{self, SignalHandler},
|
||||
Signal,
|
||||
use core::ffi::c_int;
|
||||
|
||||
use yggdrasil_rt::{
|
||||
process::{
|
||||
signal::{self, SignalHandler},
|
||||
ExitCode, Signal,
|
||||
},
|
||||
sync::rwlock::RwLock,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::{EResult, TryFromExt},
|
||||
headers::signal::{sig_handler_t, SigNumber},
|
||||
error::EResult,
|
||||
headers::{
|
||||
errno::Errno,
|
||||
signal::{sig_handler_t, signum_to_int, SIGNAL_MAX},
|
||||
},
|
||||
};
|
||||
|
||||
const SIGNAL_STACK_SIZE: usize = 4096 * 8;
|
||||
|
||||
// These are just stubs for addresses, which get converted into Rust handlers
|
||||
static SIGNAL_TABLE: RwLock<[Option<unsafe extern "C" fn(c_int)>; SIGNAL_MAX as usize]> =
|
||||
RwLock::new([None; SIGNAL_MAX as usize]);
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __sig_ignore(_signum: SigNumber) {
|
||||
unsafe extern "C" fn __sig_ignore(_signum: c_int) {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __sig_terminate(_signum: SigNumber) {
|
||||
unsafe extern "C" fn __sig_terminate(_signum: c_int) {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub unsafe fn set(sig: SigNumber, handler: sig_handler_t) -> EResult<sig_handler_t> {
|
||||
let signal = Signal::e_try_from(sig)?;
|
||||
fn signal_handler(signal: Signal) {
|
||||
let signum = signum_to_int(signal);
|
||||
if let Some(entry) = SIGNAL_TABLE.read()[signum as usize] {
|
||||
unsafe { entry(signum) };
|
||||
} else {
|
||||
let pid = unsafe { yggdrasil_rt::sys::get_pid() }.into_raw();
|
||||
log::error!("{pid}: terminated by signal {signal:?}");
|
||||
unsafe { yggdrasil_rt::sys::exit_process(ExitCode::BySignal(Ok(signal))) };
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn set(sig: c_int, handler: sig_handler_t) -> EResult<sig_handler_t> {
|
||||
if sig < 0 || sig >= SIGNAL_MAX {
|
||||
return EResult::Err(Errno::EINVAL);
|
||||
}
|
||||
|
||||
let mut table = SIGNAL_TABLE.write();
|
||||
// let signal = int_to_signum(sig)?;
|
||||
let address = handler as usize;
|
||||
let handler = match handler {
|
||||
// Transform special cases into Rust signal handlers instead
|
||||
@ -32,14 +57,11 @@ pub unsafe fn set(sig: SigNumber, handler: sig_handler_t) -> EResult<sig_handler
|
||||
// This is safe: handler essentially has the same type, just in a wrapper
|
||||
_ => core::mem::transmute(handler),
|
||||
};
|
||||
let old = signal::set_handler(signal, SignalHandler::C(handler));
|
||||
let old = table[sig as usize].replace(handler);
|
||||
|
||||
let old = match old {
|
||||
// Transform Rust special cases into C "handlers"
|
||||
SignalHandler::Ignore => __sig_ignore,
|
||||
SignalHandler::Terminate => __sig_terminate,
|
||||
// libc doesn't set Rust signal handlers, return terminate just in case
|
||||
SignalHandler::Rust(_) => __sig_terminate,
|
||||
SignalHandler::C(handler) => core::mem::transmute(handler),
|
||||
Some(old) => core::mem::transmute(old),
|
||||
None => __sig_terminate as sig_handler_t,
|
||||
};
|
||||
EResult::Ok(old)
|
||||
}
|
||||
@ -52,4 +74,6 @@ pub fn init(main: bool) {
|
||||
} else {
|
||||
signal::setup_signal_stack(SIGNAL_STACK_SIZE).expect("Couldn't setup thread signal stack");
|
||||
}
|
||||
|
||||
signal::set_all_handlers(SignalHandler::Rust(signal_handler));
|
||||
}
|
||||
|
@ -58,6 +58,10 @@ name = "kmod"
|
||||
path = "src/kmod.rs"
|
||||
|
||||
# /bin
|
||||
[[bin]]
|
||||
name = "echo"
|
||||
path = "src/echo.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "ls"
|
||||
path = "src/ls.rs"
|
||||
|
10
userspace/sysutils/src/echo.rs
Normal file
10
userspace/sysutils/src/echo.rs
Normal file
@ -0,0 +1,10 @@
|
||||
fn main() {
|
||||
let args = std::env::args().skip(1);
|
||||
for (i, arg) in args.enumerate() {
|
||||
if i != 0 {
|
||||
print!(" ");
|
||||
}
|
||||
print!("{arg}");
|
||||
}
|
||||
println!();
|
||||
}
|
@ -250,7 +250,8 @@ impl Entry {
|
||||
#[cfg(any(target_os = "yggdrasil", rust_analyzer))]
|
||||
impl Entry {
|
||||
pub fn is_device(&self) -> bool {
|
||||
self.ty.map_or(false, |d| d.is_block_device() || d.is_char_device())
|
||||
self.ty
|
||||
.map_or(false, |d| d.is_block_device() || d.is_char_device())
|
||||
}
|
||||
|
||||
pub fn is_executable(&self) -> bool {
|
||||
@ -285,6 +286,7 @@ impl MetadataImpl for Metadata {
|
||||
}
|
||||
|
||||
fn convert_file_time(time: SystemTime) -> chrono::DateTime<chrono::Utc> {
|
||||
log::info!("time = {time:?}");
|
||||
let timestamp = time.duration_since(SystemTime::UNIX_EPOCH).unwrap();
|
||||
chrono::DateTime::from_timestamp(timestamp.as_secs() as _, 0).unwrap()
|
||||
}
|
||||
@ -550,6 +552,7 @@ fn run(opts: &Args) -> Vec<Result<(), io::Error>> {
|
||||
}
|
||||
|
||||
pub fn main() -> ExitCode {
|
||||
logsink::setup_logging(false);
|
||||
let mut args = Args::parse();
|
||||
|
||||
if !stdout().is_terminal() {
|
||||
|
@ -1,13 +1,26 @@
|
||||
#![feature(rustc_private, yggdrasil_os)]
|
||||
use runtime::{abi as yggdrasil_abi, rt as yggdrasil_rt};
|
||||
use std::{
|
||||
os::yggdrasil::io::device::{mount_raw, MountOptions},
|
||||
io,
|
||||
process::ExitCode,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use yggdrasil_abi::io::MountOptions;
|
||||
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("{0}")]
|
||||
Io(#[from] io::Error),
|
||||
#[error("Timed out")]
|
||||
TimedOut,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
struct Args {
|
||||
#[arg(short, help = "Wait for the device to become present in N seconds")]
|
||||
wait: Option<u64>,
|
||||
#[arg(short)]
|
||||
ty: Option<String>,
|
||||
#[arg(short)]
|
||||
@ -16,6 +29,36 @@ struct Args {
|
||||
target: Option<String>,
|
||||
}
|
||||
|
||||
fn try_mount(options: &MountOptions) -> io::Result<()> {
|
||||
unsafe { yggdrasil_rt::sys::mount(options) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(args: &Args, options: &MountOptions) -> Result<(), Error> {
|
||||
let start = Instant::now();
|
||||
let timeout = args.wait.map(Duration::from_secs);
|
||||
|
||||
loop {
|
||||
match try_mount(options) {
|
||||
Ok(()) => return Ok(()),
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => {
|
||||
if let Some(timeout) = timeout {
|
||||
if start.elapsed() >= timeout {
|
||||
return Err(Error::TimedOut);
|
||||
} else {
|
||||
std::thread::sleep(Duration::from_millis(100));
|
||||
}
|
||||
} else {
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let args = Args::parse();
|
||||
|
||||
@ -30,18 +73,14 @@ fn main() -> ExitCode {
|
||||
let options = options.as_deref();
|
||||
|
||||
// Permissions are not yet implemented, lol
|
||||
let result = unsafe {
|
||||
let options = MountOptions {
|
||||
source,
|
||||
filesystem,
|
||||
options,
|
||||
target,
|
||||
};
|
||||
|
||||
mount_raw(&options)
|
||||
let options = MountOptions {
|
||||
source,
|
||||
filesystem,
|
||||
options,
|
||||
target,
|
||||
};
|
||||
|
||||
match result {
|
||||
match run(&args, &options) {
|
||||
Ok(()) => ExitCode::SUCCESS,
|
||||
Err(err) => {
|
||||
eprintln!("mount: {:?}", err);
|
||||
|
@ -30,10 +30,14 @@ pub mod syntax;
|
||||
pub enum Error {
|
||||
#[error("{0}")]
|
||||
Io(#[from] io::Error),
|
||||
#[error("Invalid usage")]
|
||||
InvalidUsage,
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct ShellArgs {
|
||||
#[arg(short)]
|
||||
command: Option<String>,
|
||||
#[arg(short)]
|
||||
login: bool,
|
||||
script: Option<String>,
|
||||
@ -67,6 +71,38 @@ impl ShellInput {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_single(env: &Env, command: &str) -> Outcome {
|
||||
let line = command.trim();
|
||||
|
||||
let command = match parse_interactive(line) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
eprintln!("Syntax error: {e}");
|
||||
return Outcome::err();
|
||||
}
|
||||
};
|
||||
let command = match command.expand(env) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
eprintln!("{e}");
|
||||
return Outcome::err();
|
||||
}
|
||||
};
|
||||
let (outcome, exit) = match exec::eval(command) {
|
||||
Ok(res) => res,
|
||||
Err(error) => {
|
||||
eprintln!("{error}");
|
||||
return Outcome::err();
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(exit) = exit {
|
||||
exit.exit_process();
|
||||
}
|
||||
|
||||
outcome
|
||||
}
|
||||
|
||||
fn run(mut input: ShellInput, env: &Env) -> Result<(), Error> {
|
||||
let mut line = String::new();
|
||||
loop {
|
||||
@ -140,16 +176,27 @@ fn find_script<P: AsRef<Path>>(arg: &P) -> &Path {
|
||||
}
|
||||
|
||||
fn run_wrapper(args: ShellArgs, env: &mut Env) -> Result<(), Error> {
|
||||
match args.script {
|
||||
Some(script) => {
|
||||
let shell_name = std::env::args().next().unwrap();
|
||||
match (args.command, args.script) {
|
||||
(Some(_), Some(_)) => {
|
||||
eprintln!("{shell_name}: cannot mix '-c' and regular arguments");
|
||||
Err(Error::InvalidUsage)
|
||||
}
|
||||
(Some(command), None) => match run_single(env, &command) {
|
||||
Outcome::ExitShell(_) => unreachable!(),
|
||||
Outcome::Process(status) if status.success() => ExitCode::SUCCESS.exit_process(),
|
||||
Outcome::Process(status) if let Some(code) = status.code() => std::process::exit(code),
|
||||
Outcome::Process(_) => todo!(),
|
||||
Outcome::Builtin(code) => code.exit_process(),
|
||||
},
|
||||
(None, Some(script)) => {
|
||||
let script_path = find_script(&script);
|
||||
let script_path_str = script_path.to_str().unwrap();
|
||||
env.put_var("0", script_path_str.into());
|
||||
let script = BufReader::new(File::open(script_path)?);
|
||||
run(ShellInput::File(script), env)
|
||||
}
|
||||
None => {
|
||||
let shell_name = std::env::args().next().unwrap();
|
||||
(None, None) => {
|
||||
env.put_var("0", shell_name.into());
|
||||
run(ShellInput::Interactive, env)
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ const PROGRAMS: &[(&str, &str)] = &[
|
||||
// shell
|
||||
("shell", "bin/sh"),
|
||||
// sysutils
|
||||
("echo", "bin/echo"),
|
||||
("mount", "sbin/mount"),
|
||||
("login", "sbin/login"),
|
||||
("strace", "bin/strace"),
|
||||
@ -150,8 +151,6 @@ fn build_rootfs<S: AsRef<Path>, D: AsRef<Path>>(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO this is a temporary hack
|
||||
fs::create_dir_all(rootfs_dir.join("lib"))?;
|
||||
// TODO other architectures
|
||||
util::copy_file(
|
||||
env.workspace_root.join(format!(
|
||||
@ -162,13 +161,6 @@ fn build_rootfs<S: AsRef<Path>, D: AsRef<Path>>(
|
||||
rootfs_dir.join("dynload-program"),
|
||||
)?;
|
||||
|
||||
let libstd_so = env.workspace_root.join(format!(
|
||||
"toolchain/build/host/stage1-std/{}-unknown-yggdrasil/release/libstd.so",
|
||||
env.arch.name()
|
||||
));
|
||||
|
||||
util::copy_file(libstd_so, rootfs_dir.join("lib/libstd.so"))?;
|
||||
|
||||
log::info!("Installing extras");
|
||||
for (src, dst) in install_extra {
|
||||
util::copy_file(src, rootfs_dir.join(dst))?;
|
||||
|
Loading…
x
Reference in New Issue
Block a user