alnyan/yggdrasil: migrate sources to 1.94.0
This commit is contained in:
@@ -42,3 +42,4 @@ pub(crate) mod windows_msvc;
|
||||
pub(crate) mod windows_uwp_gnu;
|
||||
pub(crate) mod windows_uwp_msvc;
|
||||
pub(crate) mod xtensa;
|
||||
pub(crate) mod yggdrasil;
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
use crate::spec::{
|
||||
Cc, LinkOutputKind, LinkerFlavor, Lld, Os, RelocModel, StackProbeType, TargetOptions,
|
||||
crt_objects,
|
||||
};
|
||||
|
||||
pub(crate) fn opts() -> TargetOptions {
|
||||
let pre_link_args = TargetOptions::link_args(
|
||||
LinkerFlavor::Gnu(Cc::No, Lld::No),
|
||||
&["-zmax-page-size=4096", "--dynamic-linker=/libexec/dyn-loader"],
|
||||
);
|
||||
|
||||
TargetOptions {
|
||||
os: Os::Yggdrasil,
|
||||
|
||||
linker: Some("rust-lld".into()),
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
|
||||
pre_link_objects: crt_objects::new(&[
|
||||
(LinkOutputKind::DynamicNoPicExe, &["rust_entry0.o"]),
|
||||
(LinkOutputKind::DynamicPicExe, &["rust_entry0.o"]),
|
||||
(LinkOutputKind::StaticNoPicExe, &["rust_entry0.o"]),
|
||||
(LinkOutputKind::StaticPicExe, &["rust_entry0.o"]),
|
||||
]),
|
||||
executables: true,
|
||||
dynamic_linking: true,
|
||||
position_independent_executables: true,
|
||||
relocation_model: RelocModel::Pic,
|
||||
|
||||
pre_link_args,
|
||||
stack_probes: StackProbeType::Inline,
|
||||
max_atomic_width: Some(128),
|
||||
eh_frame_header: false,
|
||||
has_thread_local: true,
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -1801,6 +1801,10 @@ supported_targets! {
|
||||
("x86_64-lynx-lynxos178", x86_64_lynx_lynxos178),
|
||||
|
||||
("x86_64-pc-cygwin", x86_64_pc_cygwin),
|
||||
|
||||
("aarch64-unknown-yggdrasil", aarch64_unknown_yggdrasil),
|
||||
("riscv64-unknown-yggdrasil", riscv64_unknown_yggdrasil),
|
||||
("x86_64-unknown-yggdrasil", x86_64_unknown_yggdrasil),
|
||||
}
|
||||
|
||||
/// Cow-Vec-Str: Cow<'static, [Cow<'static, str>]>
|
||||
@@ -1994,6 +1998,7 @@ crate::target_spec_enum! {
|
||||
Windows = "windows",
|
||||
Xous = "xous",
|
||||
Zkvm = "zkvm",
|
||||
Yggdrasil = "yggdrasil",
|
||||
Unknown = "unknown",
|
||||
}
|
||||
other_variant = Other;
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
use crate::spec::{Arch, PanicStrategy, Target, TargetMetadata};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
let mut base = crate::spec::base::yggdrasil::opts();
|
||||
|
||||
base.disable_redzone = true;
|
||||
base.panic_strategy = PanicStrategy::Abort;
|
||||
base.features = "+fp-armv8,+neon,+strict-align,+v8a".into();
|
||||
base.plt_by_default = true;
|
||||
|
||||
Target {
|
||||
llvm_target: "aarch64-unknown-none".into(),
|
||||
pointer_width: 64,
|
||||
arch: Arch::AArch64,
|
||||
data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
metadata: TargetMetadata {
|
||||
description: Some("AArch64 yggdrasil".into()),
|
||||
tier: Some(1),
|
||||
host_tools: Some(true),
|
||||
std: Some(true),
|
||||
},
|
||||
options: base,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
use crate::spec::{Arch, CodeModel, PanicStrategy, Target, TargetMetadata, TargetOptions};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
let base = crate::spec::base::yggdrasil::opts();
|
||||
|
||||
Target {
|
||||
llvm_target: "riscv64".into(),
|
||||
pointer_width: 64,
|
||||
arch: Arch::RiscV64,
|
||||
data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
|
||||
metadata: TargetMetadata {
|
||||
description: Some("RISC-V 64-bit yggdrasil".into()),
|
||||
tier: Some(1),
|
||||
host_tools: Some(false),
|
||||
std: Some(true),
|
||||
},
|
||||
options: TargetOptions {
|
||||
code_model: Some(CodeModel::Medium),
|
||||
disable_redzone: true,
|
||||
max_atomic_width: Some(64),
|
||||
features: "+m,+a,+c,+zicsr,+zifencei".into(),
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
llvm_abiname: "lp64".into(),
|
||||
plt_by_default: true,
|
||||
|
||||
..base // From android
|
||||
// features: "+m,+a,+f,+d,+c,+b,+v,+zicsr,+zifencei".into(),
|
||||
// supported_sanitizers: SanitizerSet::ADDRESS,
|
||||
// supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
use crate::spec::{Arch, PanicStrategy, Target, TargetMetadata};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
let mut base = crate::spec::base::yggdrasil::opts();
|
||||
|
||||
base.disable_redzone = true;
|
||||
base.panic_strategy = PanicStrategy::Abort;
|
||||
base.plt_by_default = true;
|
||||
base.features = "+sse,+cx16".into();
|
||||
|
||||
Target {
|
||||
llvm_target: "x86_64-unknown-linux-gnu".into(),
|
||||
pointer_width: 64,
|
||||
arch: Arch::X86_64,
|
||||
data_layout:
|
||||
"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(),
|
||||
metadata: TargetMetadata {
|
||||
description: Some("x86_64 yggdrasil".into()),
|
||||
tier: Some(1),
|
||||
host_tools: Some(true),
|
||||
std: Some(true),
|
||||
},
|
||||
options: base,
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,31 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "abi-generator"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "abi-lib"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "abi-serde"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.25.1"
|
||||
@@ -153,6 +178,22 @@ dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.8"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libyalloc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rustc-std-workspace-core",
|
||||
"yggdrasil-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.6"
|
||||
@@ -213,6 +254,25 @@ dependencies = [
|
||||
"unwind",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc_macro"
|
||||
version = "0.0.0"
|
||||
@@ -229,6 +289,15 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.3.0"
|
||||
@@ -331,6 +400,7 @@ dependencies = [
|
||||
"hashbrown",
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"libyalloc",
|
||||
"miniz_oxide",
|
||||
"moto-rt",
|
||||
"object",
|
||||
@@ -347,6 +417,7 @@ dependencies = [
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
"wasi 0.14.4+wasi-0.2.4",
|
||||
"windows-targets 0.0.0",
|
||||
"yggdrasil-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -358,6 +429,17 @@ dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sysroot"
|
||||
version = "0.0.0"
|
||||
@@ -378,6 +460,32 @@ dependencies = [
|
||||
"std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "unwind"
|
||||
version = "0.0.0"
|
||||
@@ -520,3 +628,30 @@ dependencies = [
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yggdrasil-abi"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"abi-generator",
|
||||
"abi-lib",
|
||||
"abi-serde",
|
||||
"prettyplease",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yggdrasil-rt"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"abi-generator",
|
||||
"abi-lib",
|
||||
"abi-serde",
|
||||
"cc",
|
||||
"libm",
|
||||
"prettyplease",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#![feature(no_core, lang_items, auto_traits)]
|
||||
#![allow(internal_features)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![no_main]
|
||||
|
||||
#[lang = "pointee_sized"]
|
||||
pub trait PointeeSized {}
|
||||
#[lang = "meta_sized"]
|
||||
pub trait MetaSized: PointeeSized {}
|
||||
#[lang = "sized"]
|
||||
pub trait Sized: MetaSized {}
|
||||
|
||||
#[lang = "sync"]
|
||||
auto trait Sync {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
#[lang = "freeze"]
|
||||
auto trait Freeze {}
|
||||
|
||||
impl ::Copy for usize {}
|
||||
|
||||
// #[lang = "drop_in_place"]
|
||||
// #[inline]
|
||||
// #[allow(unconditional_recursion)]
|
||||
// pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
|
||||
// drop_in_place(to_drop);
|
||||
// }
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
unsafe extern "C" fn _start(arg: usize) -> ! {
|
||||
extern "C" {
|
||||
fn __rust_start(arg: usize, main: usize) -> !;
|
||||
fn main(argc: isize, argv: *const *const u8) -> i32;
|
||||
}
|
||||
|
||||
__rust_start(arg, main as *const () as usize)
|
||||
}
|
||||
@@ -102,6 +102,10 @@ vex-sdk = { version = "0.27.0", features = [
|
||||
'rustc-dep-of-std',
|
||||
], default-features = false }
|
||||
|
||||
[target.'cfg(target_os = "yggdrasil")'.dependencies]
|
||||
yggdrasil-rt = { path = "../../../lib/runtime", features = ['rustc-dep-of-std'] }
|
||||
libyalloc = { path = "../../../lib/libyalloc", features = ['rustc-dep-of-std'] }
|
||||
|
||||
[features]
|
||||
backtrace = [
|
||||
'addr2line/rustc-dep-of-std',
|
||||
|
||||
@@ -57,6 +57,7 @@ fn main() {
|
||||
|| target_os == "nuttx"
|
||||
|| target_os == "cygwin"
|
||||
|| target_os == "vexos"
|
||||
|| target_os == "yggdrasil"
|
||||
|
||||
// See src/bootstrap/src/core/build_steps/synthetic_targets.rs
|
||||
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
|
||||
|
||||
@@ -183,6 +183,8 @@ pub mod vita;
|
||||
pub mod vxworks;
|
||||
#[cfg(target_os = "xous")]
|
||||
pub mod xous;
|
||||
#[cfg(target_os = "yggdrasil")]
|
||||
pub mod yggdrasil;
|
||||
|
||||
#[cfg(any(
|
||||
unix,
|
||||
@@ -194,5 +196,9 @@ pub mod xous;
|
||||
))]
|
||||
pub mod fd;
|
||||
|
||||
#[stable(feature = "os_fd", since = "1.66.0")]
|
||||
#[cfg(target_os = "yggdrasil")]
|
||||
pub use yggdrasil::io::fd;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin", doc))]
|
||||
mod net;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::io::FileMode;
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::fs::{FileType, Metadata, OpenOptions};
|
||||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::sys::{AsInner, AsInnerMut};
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub trait MetadataExt {
|
||||
fn mode_ext(&self) -> FileMode;
|
||||
fn inode(&self) -> Option<u32>;
|
||||
fn block_count(&self) -> u64;
|
||||
fn block_size(&self) -> u64;
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub trait FileTypeExt {
|
||||
fn is_block_device(&self) -> bool;
|
||||
fn is_char_device(&self) -> bool;
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub trait OpenOptionsExt {
|
||||
fn mode_ext(&mut self, mode: FileMode) -> &mut Self;
|
||||
}
|
||||
|
||||
impl MetadataExt for Metadata {
|
||||
fn mode_ext(&self) -> FileMode {
|
||||
self.as_inner().mode_ext()
|
||||
}
|
||||
|
||||
fn inode(&self) -> Option<u32> {
|
||||
self.as_inner().inode()
|
||||
}
|
||||
|
||||
fn block_count(&self) -> u64 {
|
||||
self.as_inner().block_count()
|
||||
}
|
||||
|
||||
fn block_size(&self) -> u64 {
|
||||
self.as_inner().block_size()
|
||||
}
|
||||
}
|
||||
|
||||
impl OpenOptionsExt for OpenOptions {
|
||||
fn mode_ext(&mut self, mode: FileMode) -> &mut Self {
|
||||
self.as_inner_mut().mode = mode;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl FileTypeExt for FileType {
|
||||
#[inline]
|
||||
fn is_block_device(&self) -> bool {
|
||||
self.as_inner().is_block_device()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_char_device(&self) -> bool {
|
||||
self.as_inner().is_char_device()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(target: P, path: Q) -> Result<(), io::Error> {
|
||||
let target = target.as_ref().to_str().unwrap();
|
||||
let path = path.as_ref().to_str().unwrap();
|
||||
|
||||
unsafe { syscall::create_symlink(None, target, path) }?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::io::device as rt;
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::io;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub type MountOptions<'a> = rt::MountOptions<'a>;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub type UnmountOptions = rt::UnmountOptions;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub unsafe fn mount_raw(options: &MountOptions<'_>) -> io::Result<()> {
|
||||
syscall::mount(options)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
mod owned;
|
||||
mod raw;
|
||||
|
||||
pub use owned::*;
|
||||
pub use raw::*;
|
||||
|
||||
use crate::io;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn clone_fd(src: RawFd) -> io::Result<RawFd> {
|
||||
Ok(unsafe { yggdrasil_rt::sys::clone_fd(src, None) }?)
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
#![stable(feature = "io_safety", since = "1.63.0")]
|
||||
|
||||
use super::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem::forget;
|
||||
use crate::sys::IntoInner;
|
||||
|
||||
macro_rules! stdio_impl_as_fd {
|
||||
($($ty:ty => $n:expr),*) => {$(
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl AsFd for $ty {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
BorrowedFd {
|
||||
fd: $n,
|
||||
_pd: PhantomData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #[stable(feature = "io_safety", since = "1.21.0")]
|
||||
// impl AsFd for &$ty {
|
||||
// #[inline]
|
||||
// fn as_raw_fd(&self) -> RawFd {
|
||||
// $n
|
||||
// }
|
||||
// }
|
||||
)*};
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct OwnedFd {
|
||||
fd: RawFd,
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct BorrowedFd<'fd> {
|
||||
fd: RawFd,
|
||||
_pd: PhantomData<&'fd OwnedFd>,
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
pub trait AsFd {
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
fn as_fd(&self) -> BorrowedFd<'_>;
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl<T: AsFd> AsFd for &T {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
T::as_fd(self)
|
||||
}
|
||||
}
|
||||
|
||||
// Borrowed
|
||||
|
||||
impl BorrowedFd<'_> {
|
||||
#[rustc_const_stable(feature = "io_safety", since = "1.63.0")]
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
|
||||
// assert_ne!(fd, u32::MAX as RawFd);
|
||||
Self { fd, _pd: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl AsFd for BorrowedFd<'_> {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl AsRawFd for BorrowedFd<'_> {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
// Owned
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl AsFd for OwnedFd {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl IntoRawFd for OwnedFd {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
let fd = self.fd;
|
||||
forget(self);
|
||||
fd
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl FromRawFd for OwnedFd {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
Self { fd }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl AsRawFd for OwnedFd {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl Drop for OwnedFd {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::close(self.fd).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: AsFd for File, From<File> for OwnedFd, From<OwnedFd> for File,
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl From<crate::fs::File> for OwnedFd {
|
||||
fn from(value: crate::fs::File) -> OwnedFd {
|
||||
let inner = value.into_inner();
|
||||
Self { fd: inner.into_raw_fd() }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "io_safety", since = "1.63.0")]
|
||||
impl AsFd for crate::fs::File {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
BorrowedFd { fd: self.as_raw_fd(), _pd: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
stdio_impl_as_fd!(
|
||||
crate::io::Stdin => RawFd::STDIN,
|
||||
crate::io::Stdout => RawFd::STDOUT,
|
||||
crate::io::Stderr => RawFd::STDERR
|
||||
);
|
||||
stdio_impl_as_fd!(
|
||||
crate::io::StdinLock<'_> => RawFd::STDIN,
|
||||
crate::io::StdoutLock<'_> => RawFd::STDOUT,
|
||||
crate::io::StderrLock<'_> => RawFd::STDERR
|
||||
);
|
||||
@@ -0,0 +1,98 @@
|
||||
#![stable(feature = "os_fd", since = "1.66.0")]
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub type RawFd = yggdrasil_rt::io::RawFd;
|
||||
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
|
||||
macro_rules! stdio_impl_as_raw_fd {
|
||||
($($ty:ty => $n:expr),*) => {$(
|
||||
#[stable(feature = "asraw_stdio", since = "1.21.0")]
|
||||
impl AsRawFd for $ty {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
$n
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "asraw_stdio", since = "1.21.0")]
|
||||
impl AsRawFd for &$ty {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
$n
|
||||
}
|
||||
}
|
||||
)*};
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait AsRawFd {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn as_raw_fd(&self) -> RawFd;
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait FromRawFd {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self;
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait IntoRawFd {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn into_raw_fd(self) -> RawFd;
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl AsRawFd for RawFd {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl FromRawFd for RawFd {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
fd
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl IntoRawFd for RawFd {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
stdio_impl_as_raw_fd!(
|
||||
crate::io::Stdin => RawFd::STDIN,
|
||||
crate::io::Stdout => RawFd::STDOUT,
|
||||
crate::io::Stderr => RawFd::STDERR
|
||||
);
|
||||
stdio_impl_as_raw_fd!(
|
||||
crate::io::StdinLock<'_> => RawFd::STDIN,
|
||||
crate::io::StdoutLock<'_> => RawFd::STDOUT,
|
||||
crate::io::StderrLock<'_> => RawFd::STDERR
|
||||
);
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl AsRawFd for crate::fs::File {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.as_inner().as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl FromRawFd for crate::fs::File {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
let inner = crate::sys::fs::File::from_raw_fd(fd);
|
||||
crate::fs::File::from_inner(inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl IntoRawFd for crate::fs::File {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.into_inner().into_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use super::fd::RawFd;
|
||||
use crate::os::fd::{AsRawFd, OwnedFd};
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub struct FileMapping<'a> {
|
||||
data: &'a mut [u8],
|
||||
fd: OwnedFd,
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl<'a> FileMapping<'a> {
|
||||
pub fn new<F: Into<OwnedFd>>(f: F, offset: u64, len: usize) -> crate::io::Result<Self> {
|
||||
use yggdrasil_rt::mem::{MappingFlags, MappingSource};
|
||||
|
||||
let owned_fd = f.into();
|
||||
let raw_fd = owned_fd.as_raw_fd();
|
||||
let base = unsafe {
|
||||
yggdrasil_rt::sys::map_memory(
|
||||
None,
|
||||
len,
|
||||
MappingFlags::WRITE,
|
||||
&MappingSource::File(raw_fd, offset),
|
||||
)
|
||||
}?;
|
||||
|
||||
#[allow(fuzzy_provenance_casts)]
|
||||
let data = unsafe { crate::slice::from_raw_parts_mut(base as *mut u8, len) };
|
||||
|
||||
Ok(Self { data, fd: owned_fd })
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl crate::ops::Deref for FileMapping<'_> {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl crate::ops::DerefMut for FileMapping<'_> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl Drop for FileMapping<'_> {
|
||||
fn drop(&mut self) {
|
||||
// Unmap the memory
|
||||
let base = self.data.as_ptr() as usize;
|
||||
let len = self.data.len();
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::unmap_memory(base, len).expect("Memory unmap failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for FileMapping<'_> {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd.as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub mod fd;
|
||||
|
||||
pub mod device;
|
||||
pub mod mapping;
|
||||
// pub mod message_channel;
|
||||
pub mod net;
|
||||
//pub mod pid;
|
||||
pub mod pipe;
|
||||
pub mod poll;
|
||||
pub mod shared_memory;
|
||||
pub mod terminal;
|
||||
pub mod timer;
|
||||
|
||||
pub use yggdrasil_rt::io::{FileMetadataUpdate, FileMetadataUpdateMode, FileMode as RawFileMode};
|
||||
|
||||
pub fn update_metadata<P: AsRef<crate::path::Path>>(
|
||||
path: P,
|
||||
update: &FileMetadataUpdate,
|
||||
) -> crate::io::Result<()> {
|
||||
let path = path.as_ref().to_str().unwrap();
|
||||
unsafe { yggdrasil_rt::sys::update_metadata(None, path, &update) }?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod raw_socket;
|
||||
@@ -0,0 +1,41 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::net::{self as rt, SocketInterfaceQuery};
|
||||
|
||||
use crate::io;
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
use crate::sys::fd::FileDesc;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub struct RawSocket(FileDesc);
|
||||
|
||||
impl RawSocket {
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn bind<'a, Q: Into<SocketInterfaceQuery<'a>>>(interface: Q) -> io::Result<Self> {
|
||||
let query = interface.into();
|
||||
let raw = rt::bind_raw(query)?;
|
||||
let inner = unsafe { FileDesc::from_raw_fd(raw) };
|
||||
Ok(Self(inner))
|
||||
}
|
||||
|
||||
pub fn send(&self, data: &[u8]) -> io::Result<usize> {
|
||||
Ok(rt::socket::send(self.as_raw_fd(), data)?)
|
||||
}
|
||||
|
||||
pub fn recv(&self, data: &mut [u8]) -> io::Result<usize> {
|
||||
Ok(rt::socket::receive(self.as_raw_fd(), data)?)
|
||||
}
|
||||
|
||||
pub fn hardware_address(&self) -> io::Result<[u8; 6]> {
|
||||
rt::get_socket_option!(self.as_raw_fd(), rt::options::BoundHardwareAddress)
|
||||
.map(Into::into)
|
||||
.map_err(io::Error::from)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl AsRawFd for RawSocket {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::io as rt;
|
||||
|
||||
use crate::os::fd::{FromRawFd, OwnedFd};
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn create_pipe_pair(
|
||||
read_nonblocking: bool,
|
||||
write_nonblocking: bool,
|
||||
) -> crate::io::Result<(OwnedFd, OwnedFd)> {
|
||||
let (read, write) = rt::create_pipe_pair(read_nonblocking, write_nonblocking)?;
|
||||
let read = unsafe { OwnedFd::from_raw_fd(read) };
|
||||
let write = unsafe { OwnedFd::from_raw_fd(write) };
|
||||
|
||||
Ok((read, write))
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::io::poll as rt;
|
||||
|
||||
use crate::io;
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd};
|
||||
use crate::time::Duration;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub type PollControl = rt::PollControl;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub struct PollChannel(OwnedFd);
|
||||
|
||||
impl PollChannel {
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn new() -> io::Result<Self> {
|
||||
let raw_fd = unsafe { yggdrasil_rt::sys::create_poll_channel() }?;
|
||||
let fd = unsafe { OwnedFd::from_raw_fd(raw_fd) };
|
||||
Ok(Self(fd))
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn add(&mut self, fd: RawFd) -> io::Result<()> {
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::poll_channel_control(self.0.as_raw_fd(), PollControl::AddFd, fd)
|
||||
}?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn remove(&mut self, fd: RawFd) -> io::Result<()> {
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::poll_channel_control(self.0.as_raw_fd(), PollControl::RemoveFd, fd)
|
||||
}?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn wait(
|
||||
&mut self,
|
||||
timeout: Option<Duration>,
|
||||
retain: bool,
|
||||
) -> io::Result<Option<(RawFd, io::Result<()>)>> {
|
||||
let mut output = None;
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::poll_channel_wait(self.0.as_raw_fd(), &timeout, retain, &mut output)
|
||||
}?;
|
||||
Ok(output.map(|(l, r)| (l, r.map_err(io::Error::from))))
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl AsRawFd for PollChannel {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::io;
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd};
|
||||
use crate::os::yggdrasil::io::mapping::FileMapping;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub struct SharedMemory(OwnedFd, usize);
|
||||
|
||||
impl SharedMemory {
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn new(size: usize) -> io::Result<Self> {
|
||||
let raw_fd = unsafe { syscall::create_shared_memory(size) }?;
|
||||
let fd = unsafe { OwnedFd::from_raw_fd(raw_fd) };
|
||||
Ok(Self(fd, size))
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn size(&self) -> usize {
|
||||
self.1
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn into_mapping<'a>(self) -> io::Result<FileMapping<'a>> {
|
||||
FileMapping::new(self.0, 0, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl Into<OwnedFd> for SharedMemory {
|
||||
fn into(self) -> OwnedFd {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl AsRawFd for SharedMemory {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::io::{FileMode, OpenOptions, terminal as rt};
|
||||
use yggdrasil_rt::process::ProcessGroupId;
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::fs::File;
|
||||
use crate::io;
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
use crate::path::Path;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub type TerminalOptions = rt::TerminalOptions;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub type TerminalSize = rt::TerminalSize;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub unsafe fn set_terminal_options<F: AsRawFd>(fd: &F, opt: &TerminalOptions) -> io::Result<()> {
|
||||
rt::set_terminal_options(fd.as_raw_fd(), opt)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub unsafe fn get_terminal_options<F: AsRawFd>(fd: &F) -> io::Result<TerminalOptions> {
|
||||
Ok(rt::get_terminal_options(fd.as_raw_fd())?)
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub unsafe fn set_terminal_group<F: AsRawFd>(fd: &F, group: ProcessGroupId) -> io::Result<()> {
|
||||
Ok(rt::set_terminal_group(fd.as_raw_fd(), group)?)
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn get_terminal_size<F: AsRawFd>(fd: &F) -> io::Result<TerminalSize> {
|
||||
Ok(rt::get_terminal_size(fd.as_raw_fd())?)
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub unsafe fn update_terminal_options<F: AsRawFd, M: FnOnce(TerminalOptions) -> TerminalOptions>(
|
||||
fd: &F,
|
||||
mutator: M,
|
||||
) -> io::Result<TerminalOptions> {
|
||||
let old = get_terminal_options(fd)?;
|
||||
let new = mutator(old);
|
||||
set_terminal_options(fd, &new)?;
|
||||
Ok(old)
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub unsafe fn start_terminal_session<P: AsRef<Path>>(terminal: P) -> io::Result<()> {
|
||||
let terminal = terminal.as_ref().to_str().unwrap();
|
||||
|
||||
syscall::start_session()?;
|
||||
|
||||
let stdin_fd = syscall::open(None, terminal, OpenOptions::READ, FileMode::empty())?;
|
||||
let stdout_stderr_fd = syscall::open(None, terminal, OpenOptions::WRITE, FileMode::empty())?;
|
||||
|
||||
syscall::clone_fd(stdin_fd, Some(RawFd::STDIN))?;
|
||||
syscall::clone_fd(stdout_stderr_fd, Some(RawFd::STDOUT))?;
|
||||
syscall::clone_fd(stdout_stderr_fd, Some(RawFd::STDERR))?;
|
||||
|
||||
syscall::close(stdin_fd)?;
|
||||
syscall::close(stdout_stderr_fd)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn create_pty(
|
||||
options: Option<TerminalOptions>,
|
||||
size: TerminalSize,
|
||||
) -> io::Result<(File, File)> {
|
||||
let options = options.unwrap_or_default();
|
||||
let mut fds = [MaybeUninit::uninit(), MaybeUninit::uninit()];
|
||||
|
||||
unsafe { syscall::create_pty(&options, &size, &mut fds) }?;
|
||||
|
||||
let master = unsafe { File::from_raw_fd(fds[0].assume_init()) };
|
||||
let slave = unsafe { File::from_raw_fd(fds[1].assume_init()) };
|
||||
|
||||
Ok((master, slave))
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
|
||||
use yggdrasil_rt::io::TimerOptions;
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::io;
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
use crate::sys::fd::FileDesc;
|
||||
use crate::time::Duration;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub struct TimerFd(FileDesc);
|
||||
|
||||
impl TimerFd {
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn new(repeat: bool, nonblocking: bool) -> io::Result<Self> {
|
||||
let mut options = TimerOptions::empty();
|
||||
if repeat {
|
||||
options |= TimerOptions::REPEAT;
|
||||
}
|
||||
let raw = unsafe { syscall::create_timer(options) }?;
|
||||
let fd = unsafe { FileDesc::from_raw_fd(raw) };
|
||||
if nonblocking {
|
||||
fd.set_nonblocking(true)?;
|
||||
}
|
||||
Ok(Self(fd))
|
||||
}
|
||||
|
||||
pub fn start(&mut self, timeout: Duration) -> io::Result<()> {
|
||||
let tval = timeout.as_micros();
|
||||
unsafe { syscall::write(self.0.as_raw_fd(), &tval.to_ne_bytes()) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_expired(&mut self) -> io::Result<bool> {
|
||||
let mut buf = [0; 1];
|
||||
match unsafe { syscall::read(self.0.as_raw_fd(), &mut buf) }.map_err(io::Error::from) {
|
||||
Ok(_) => Ok(true),
|
||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => Ok(false),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl AsRawFd for TimerFd {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#![unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
#![allow(exported_private_dependencies)]
|
||||
|
||||
pub use yggdrasil_rt as rt;
|
||||
|
||||
pub mod fs;
|
||||
pub mod io;
|
||||
pub mod process;
|
||||
pub mod signal;
|
||||
|
||||
use yggdrasil_rt::process::ProgramArgumentInner;
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::path::{Path, PathBuf};
|
||||
|
||||
pub(crate) static mut REAL_BINARY_PATH: Option<PathBuf> = None;
|
||||
|
||||
pub(crate) unsafe fn set_real_program(program_arg: &ProgramArgumentInner) {
|
||||
if let Some(real_program) = program_arg.real_program() {
|
||||
let real_program_str = real_program.to_str().expect("Invalid real_program from kernel");
|
||||
REAL_BINARY_PATH = Some(PathBuf::from(real_program_str));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn real_binary_path() -> &'static Path {
|
||||
#[allow(static_mut_refs)]
|
||||
unsafe {
|
||||
REAL_BINARY_PATH.as_deref().unwrap_or_else(|| Path::new(""))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_random(buffer: &mut [crate::mem::MaybeUninit<u8>]) {
|
||||
unsafe { syscall::get_random(buffer.assume_init_mut()) }
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#![stable(feature = "os", since = "1.0.0")]
|
||||
|
||||
use yggdrasil_rt::io::RawFd;
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub use yggdrasil_rt::process::ProcessGroupId;
|
||||
use yggdrasil_rt::process::{ProcessId, Signal, SpawnFlags};
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::io;
|
||||
use crate::path::Path;
|
||||
use crate::process::{Child, Command, ExitStatus};
|
||||
use crate::sealed::Sealed;
|
||||
use crate::sys::{AsInner, AsInnerMut};
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub trait ChildExt: Sealed {
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
fn main_thread_id(&self) -> io::Result<u32>;
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub trait CommandExt: Sealed {
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
fn process_group(&mut self, pgroup: ProcessGroupId) -> &mut Command;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
unsafe fn gain_terminal<F: Into<RawFd>>(&mut self, fd: F) -> &mut Command;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
unsafe fn attach_tracing(&mut self) -> &mut Command;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
fn disable_aslr(&mut self) -> &mut Command;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
fn change_root<P: AsRef<Path>>(&mut self, new: P) -> &mut Command;
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub trait ExitStatusExt: Sealed {
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
fn signal(&self) -> Option<Result<Signal, u32>>;
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl CommandExt for Command {
|
||||
fn process_group(&mut self, pgroup: ProcessGroupId) -> &mut Command {
|
||||
self.as_inner_mut().pgroup = Some(pgroup);
|
||||
self
|
||||
}
|
||||
|
||||
unsafe fn gain_terminal<F: Into<RawFd>>(&mut self, fd: F) -> &mut Command {
|
||||
self.as_inner_mut().gain_terminal = Some(fd.into());
|
||||
self
|
||||
}
|
||||
|
||||
unsafe fn attach_tracing(&mut self) -> &mut Command {
|
||||
self.as_inner_mut().attach_trace = true;
|
||||
self
|
||||
}
|
||||
|
||||
fn disable_aslr(&mut self) -> &mut Command {
|
||||
self.as_inner_mut().flags |= SpawnFlags::DISABLE_ASLR;
|
||||
self
|
||||
}
|
||||
|
||||
fn change_root<P: AsRef<Path>>(&mut self, new: P) -> &mut Command {
|
||||
self.as_inner_mut().change_root(new);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl ExitStatusExt for ExitStatus {
|
||||
fn signal(&self) -> Option<Result<Signal, u32>> {
|
||||
self.as_inner().signal()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl ChildExt for Child {
|
||||
fn main_thread_id(&self) -> io::Result<u32> {
|
||||
self.as_inner().main_thread_id()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn id_ext() -> ProcessId {
|
||||
unsafe { syscall::get_pid() }
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn group_id() -> ProcessGroupId {
|
||||
unsafe { syscall::get_process_group_id() }
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
pub fn create_process_group() -> ProcessGroupId {
|
||||
unsafe { syscall::create_process_group() }
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
pub use yggdrasil_rt::process::{ProcessId, Signal};
|
||||
pub use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::io;
|
||||
|
||||
#[must_use = "It is adviced to store the original handler in case it needs to be restored later"]
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum SignalHandler {
|
||||
Ignore,
|
||||
Terminate,
|
||||
Function(fn(Signal)),
|
||||
}
|
||||
|
||||
pub fn set_signal_handler(signal: Signal, handler: SignalHandler) -> SignalHandler {
|
||||
crate::sys::signal::set_signal_handler(signal, handler)
|
||||
}
|
||||
|
||||
pub fn send(destination: u32, signal: Signal) -> io::Result<()> {
|
||||
let destination = unsafe { ProcessId::from_raw(destination) };
|
||||
unsafe { syscall::send_signal(destination, signal) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn abort() -> ! {
|
||||
unsafe { syscall::send_signal(syscall::get_pid(), Signal::Aborted) }.expect("Could not abort");
|
||||
unreachable!();
|
||||
}
|
||||
@@ -107,4 +107,7 @@ cfg_select! {
|
||||
target_os = "zkvm" => {
|
||||
mod zkvm;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
use libyalloc::allocator::BucketAllocator;
|
||||
use libyalloc::sys::OsPageProvider;
|
||||
|
||||
use crate::alloc::{GlobalAlloc, Layout, System};
|
||||
use crate::cell::UnsafeCell;
|
||||
use crate::ptr::NonNull;
|
||||
use crate::sys::sync::Mutex;
|
||||
|
||||
struct Global {
|
||||
lock: Mutex,
|
||||
inner: UnsafeCell<BucketAllocator<OsPageProvider>>,
|
||||
}
|
||||
|
||||
#[stable(feature = "alloc_system_type", since = "1.28.0")]
|
||||
unsafe impl GlobalAlloc for System {
|
||||
#[inline]
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
let ptr = unsafe {
|
||||
ALLOC.lock.lock();
|
||||
let ptr = (*ALLOC.inner.get()).allocate(layout);
|
||||
ALLOC.lock.unlock();
|
||||
ptr
|
||||
};
|
||||
|
||||
if let Some(ptr) = ptr { ptr.as_ptr() } else { crate::ptr::null_mut() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
let ptr = NonNull::new(ptr).expect("Invalid pointer");
|
||||
|
||||
unsafe {
|
||||
ALLOC.lock.lock();
|
||||
(*ALLOC.inner.get()).free(ptr, layout);
|
||||
ALLOC.lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Global {
|
||||
#[rustc_const_unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
const fn new() -> Self {
|
||||
Self { lock: Mutex::new(), inner: UnsafeCell::new(BucketAllocator::new()) }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for Global {}
|
||||
|
||||
static ALLOC: Global = Global::new();
|
||||
@@ -53,6 +53,10 @@ cfg_select! {
|
||||
mod zkvm;
|
||||
pub use zkvm::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::*;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use unsupported::*;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
use crate::ffi::OsString;
|
||||
use crate::{fmt, vec};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone)]
|
||||
pub struct Args {
|
||||
iter: vec::IntoIter<OsString>,
|
||||
}
|
||||
|
||||
pub fn args() -> Args {
|
||||
Args { iter: imp::clone() }
|
||||
}
|
||||
|
||||
impl fmt::Debug for Args {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.iter, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Args {
|
||||
type Item = OsString;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExactSizeIterator for Args {
|
||||
fn len(&self) -> usize {
|
||||
self.iter.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl DoubleEndedIterator for Args {
|
||||
fn next_back(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod imp {
|
||||
use yggdrasil_rt::process::ProgramArgumentInner;
|
||||
|
||||
use crate::ffi::{OsStr, OsString};
|
||||
use crate::sync::atomic::{AtomicPtr, Ordering};
|
||||
use crate::{ptr, vec};
|
||||
|
||||
static ARGS: AtomicPtr<Vec<OsString>> = AtomicPtr::new(ptr::null_mut());
|
||||
|
||||
pub(crate) fn init(arg: &ProgramArgumentInner) {
|
||||
let mut args = Box::new(Vec::new());
|
||||
|
||||
for arg in arg.args() {
|
||||
let arg = unsafe { OsStr::from_encoded_bytes_unchecked(arg.to_bytes()) };
|
||||
args.push(arg.to_owned());
|
||||
}
|
||||
|
||||
let args = Box::into_raw(args);
|
||||
ARGS.store(args, Ordering::Release);
|
||||
}
|
||||
|
||||
pub(super) fn clone() -> vec::IntoIter<OsString> {
|
||||
unsafe {
|
||||
ARGS.load(Ordering::Acquire)
|
||||
.as_ref()
|
||||
.expect("Program arguments not yet initialized")
|
||||
.clone()
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+4
@@ -55,6 +55,10 @@ cfg_select! {
|
||||
mod zkvm;
|
||||
pub use zkvm::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::*;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use unsupported::*;
|
||||
|
||||
Vendored
+107
@@ -0,0 +1,107 @@
|
||||
use crate::collections::hash_map;
|
||||
use crate::ffi::{OsStr, OsString};
|
||||
use crate::sys::AsInner;
|
||||
use crate::{fmt, io};
|
||||
|
||||
pub struct Env {
|
||||
iter: hash_map::IntoIter<OsString, OsString>,
|
||||
}
|
||||
|
||||
impl !Send for Env {}
|
||||
impl !Sync for Env {}
|
||||
|
||||
impl Iterator for Env {
|
||||
type Item = (OsString, OsString);
|
||||
|
||||
fn next(&mut self) -> Option<(OsString, OsString)> {
|
||||
self.iter.next()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Env {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.iter, f)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn env() -> Env {
|
||||
let iter = imp::read().clone().into_iter();
|
||||
Env { iter }
|
||||
}
|
||||
|
||||
pub fn getenv(name: &OsStr) -> Option<OsString> {
|
||||
if name.as_inner().as_encoded_bytes().contains(&b'=') {
|
||||
return None;
|
||||
}
|
||||
let env = imp::read();
|
||||
env.get(name).cloned()
|
||||
}
|
||||
|
||||
pub unsafe fn setenv(name: &OsStr, value: &OsStr) -> io::Result<()> {
|
||||
if name.as_inner().as_encoded_bytes().contains(&b'=') {
|
||||
return Err(io::Error::new(io::ErrorKind::Uncategorized, "Invalid env var name"));
|
||||
}
|
||||
let mut env = imp::write();
|
||||
env.insert(name.to_owned(), value.to_owned());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub unsafe fn unsetenv(name: &OsStr) -> io::Result<()> {
|
||||
if name.as_inner().as_encoded_bytes().contains(&b'=') {
|
||||
return Err(io::Error::new(io::ErrorKind::Uncategorized, "Invalid env var name"));
|
||||
}
|
||||
let mut env = imp::write();
|
||||
env.remove(name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) mod imp {
|
||||
use yggdrasil_rt::process::ProgramArgumentInner;
|
||||
|
||||
use crate::collections::HashMap;
|
||||
use crate::ffi::{OsStr, OsString};
|
||||
use crate::ptr;
|
||||
use crate::sync::atomic::{AtomicPtr, Ordering};
|
||||
use crate::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
|
||||
static ENV: AtomicPtr<RwLock<HashMap<OsString, OsString>>> = AtomicPtr::new(ptr::null_mut());
|
||||
|
||||
pub(super) fn read() -> RwLockReadGuard<'static, HashMap<OsString, OsString>> {
|
||||
unsafe {
|
||||
ENV.load(Ordering::Acquire)
|
||||
.as_ref()
|
||||
.expect("Environment variables not initialized")
|
||||
.read()
|
||||
.expect("Could not obtain env read lock")
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn write() -> RwLockWriteGuard<'static, HashMap<OsString, OsString>> {
|
||||
unsafe {
|
||||
ENV.load(Ordering::Acquire)
|
||||
.as_ref()
|
||||
.expect("Environment variables not initialized")
|
||||
.write()
|
||||
.expect("Could not obtain env write lock")
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn init(arg: &ProgramArgumentInner) {
|
||||
let mut envs = HashMap::new();
|
||||
for pair in arg.envs() {
|
||||
let pair = pair.to_bytes();
|
||||
let Some((key, value)) = pair.split_once(|c| *c == b'=') else { continue };
|
||||
let key = unsafe { OsStr::from_encoded_bytes_unchecked(key).to_owned() };
|
||||
let value = unsafe { OsStr::from_encoded_bytes_unchecked(value).to_owned() };
|
||||
|
||||
envs.insert(key, value);
|
||||
}
|
||||
|
||||
let envs = Box::into_raw(Box::new(RwLock::new(envs)));
|
||||
ENV.store(envs, Ordering::Release);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,10 @@ cfg_select! {
|
||||
mod motor;
|
||||
pub use motor::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::*;
|
||||
}
|
||||
all(target_vendor = "fortanix", target_env = "sgx") => {
|
||||
mod sgx;
|
||||
pub use sgx::*;
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
use yggdrasil_rt::io::{self as rt, FileSync, options};
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
|
||||
use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
|
||||
use crate::sys::fs::{self, FileAttr};
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FileDesc {
|
||||
fd: OwnedFd,
|
||||
}
|
||||
|
||||
impl FileDesc {
|
||||
pub(crate) fn set_nonblocking(&self, non_blocking: bool) -> io::Result<()> {
|
||||
rt::set_file_option::<options::NonBlocking>(self.as_raw_fd(), &non_blocking)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
|
||||
Ok(unsafe { syscall::read(self.fd.as_raw_fd(), buffer) }?)
|
||||
}
|
||||
|
||||
pub(crate) fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
io::default_read_buf(|buf| self.read(buf), cursor)
|
||||
}
|
||||
|
||||
pub(crate) fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
todo!("FileDesc::read_vectored()")
|
||||
}
|
||||
|
||||
pub(crate) fn write(&self, buffer: &[u8]) -> io::Result<usize> {
|
||||
Ok(unsafe { syscall::write(self.fd.as_raw_fd(), buffer) }?)
|
||||
}
|
||||
|
||||
pub(crate) fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
todo!("FileDesc::write_vectored()")
|
||||
}
|
||||
|
||||
pub(crate) fn read_to_end(&self, buffer: &mut Vec<u8>) -> io::Result<usize> {
|
||||
let mut buf = [0; 512];
|
||||
let mut bytes_read = 0;
|
||||
|
||||
loop {
|
||||
let amount = self.read(&mut buf)?;
|
||||
if amount == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
buffer.extend_from_slice(&buf[..amount]);
|
||||
bytes_read += amount;
|
||||
}
|
||||
|
||||
Ok(bytes_read)
|
||||
}
|
||||
|
||||
pub(crate) fn try_clone(&self) -> io::Result<Self> {
|
||||
let raw = unsafe { syscall::clone_fd(self.as_raw_fd(), None) }?;
|
||||
Ok(unsafe { Self::from_raw_fd(raw) })
|
||||
}
|
||||
|
||||
pub(crate) fn metadata(&self) -> io::Result<FileAttr> {
|
||||
fs::get_metadata_inner(Some(self.as_raw_fd()), "", true)
|
||||
}
|
||||
|
||||
pub(crate) fn truncate(&self, size: u64) -> io::Result<()> {
|
||||
unsafe { syscall::truncate(self.as_raw_fd(), size) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn datasync(&self) -> io::Result<()> {
|
||||
unsafe { syscall::fsync(self.as_raw_fd(), FileSync::DATA) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn fsync(&self) -> io::Result<()> {
|
||||
unsafe { syscall::fsync(self.as_raw_fd(), FileSync::METADATA | FileSync::DATA) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
|
||||
let mut output = 0;
|
||||
unsafe { syscall::seek(self.as_raw_fd(), pos.into(), &mut output) }?;
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<OwnedFd> for FileDesc {
|
||||
fn into_inner(self) -> OwnedFd {
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<OwnedFd> for FileDesc {
|
||||
fn from_inner(fd: OwnedFd) -> Self {
|
||||
Self { fd }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for FileDesc {
|
||||
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
|
||||
unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<OwnedFd> for FileDesc {
|
||||
fn as_inner(&self) -> &OwnedFd {
|
||||
&self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl AsFd for FileDesc {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
self.fd.as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for FileDesc {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for FileDesc {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.fd.into_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#![allow(exported_private_dependencies)]
|
||||
|
||||
use yggdrasil_rt::io::SeekFrom as OsSeekFrom;
|
||||
|
||||
use crate::io::SeekFrom;
|
||||
|
||||
mod file;
|
||||
mod socket;
|
||||
|
||||
pub use file::FileDesc;
|
||||
pub(crate) use socket::SocketFileDesc;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl From<SeekFrom> for OsSeekFrom {
|
||||
fn from(value: SeekFrom) -> OsSeekFrom {
|
||||
match value {
|
||||
SeekFrom::Start(v) => OsSeekFrom::Start(v),
|
||||
SeekFrom::End(v) => OsSeekFrom::End(v),
|
||||
SeekFrom::Current(v) => OsSeekFrom::Current(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
use yggdrasil_rt::{io as rt_io, net as rt, sys as syscall};
|
||||
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
|
||||
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
|
||||
use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
use crate::time::Duration;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SocketFileDesc {
|
||||
fd: OwnedFd,
|
||||
}
|
||||
|
||||
impl SocketFileDesc {
|
||||
pub(crate) fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::RecvTimeout>(self.as_raw_fd(), &timeout)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::SendTimeout>(self.as_raw_fd(), &timeout)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn set_linger(&self, _linger: Option<Duration>) -> io::Result<()> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::set_linger()")
|
||||
}
|
||||
|
||||
pub(crate) fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::NoDelay>(self.as_raw_fd(), &nodelay)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn set_ttl(&self, ttl: u32) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::Ttl>(self.as_raw_fd(), &ttl)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
rt_io::set_file_option::<rt_io::options::NonBlocking>(self.as_raw_fd(), &nonblocking)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::Ipv6Only>(self.as_raw_fd(), &only_v6)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::Broadcast>(self.as_raw_fd(), &broadcast)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::MulticastLoopV4>(self.as_raw_fd(), &loop_v4)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::MulticastTtlV4>(self.as_raw_fd(), &ttl)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
|
||||
rt::set_socket_option::<rt::options::MulticastLoopV6>(self.as_raw_fd(), &loop_v6)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::RecvTimeout)?)
|
||||
}
|
||||
|
||||
pub(crate) fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::SendTimeout)?)
|
||||
}
|
||||
|
||||
pub(crate) fn linger(&self) -> io::Result<Option<Duration>> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::linger()")
|
||||
}
|
||||
|
||||
pub(crate) fn nodelay(&self) -> io::Result<bool> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::NoDelay)?)
|
||||
}
|
||||
|
||||
pub(crate) fn ttl(&self) -> io::Result<u32> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::Ttl)?)
|
||||
}
|
||||
|
||||
pub(crate) fn only_v6(&self) -> io::Result<bool> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::Ipv6Only)?)
|
||||
}
|
||||
|
||||
pub(crate) fn broadcast(&self) -> io::Result<bool> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::Broadcast)?)
|
||||
}
|
||||
|
||||
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::MulticastLoopV4)?)
|
||||
}
|
||||
|
||||
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::MulticastTtlV4)?)
|
||||
}
|
||||
|
||||
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
|
||||
Ok(rt::get_socket_option!(self.as_raw_fd(), rt::options::MulticastLoopV6)?)
|
||||
}
|
||||
|
||||
pub(crate) fn local_addr(&self) -> io::Result<SocketAddr> {
|
||||
Ok(rt::local_address(self.as_raw_fd())?)
|
||||
}
|
||||
|
||||
pub(crate) fn peer_addr(&self) -> io::Result<SocketAddr> {
|
||||
Ok(rt::peer_address(self.as_raw_fd())?)
|
||||
}
|
||||
|
||||
pub(crate) fn join_multicast_v4(
|
||||
&self,
|
||||
_multiaddr: &Ipv4Addr,
|
||||
_interface: &Ipv4Addr,
|
||||
) -> io::Result<()> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::join_multicast_v4()")
|
||||
}
|
||||
|
||||
pub(crate) fn join_multicast_v6(
|
||||
&self,
|
||||
_multiaddr: &Ipv6Addr,
|
||||
_interface: u32,
|
||||
) -> io::Result<()> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::join_multicast_v6()")
|
||||
}
|
||||
|
||||
pub(crate) fn leave_multicast_v4(
|
||||
&self,
|
||||
_multiaddr: &Ipv4Addr,
|
||||
_interface: &Ipv4Addr,
|
||||
) -> io::Result<()> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::leave_multicast_v4()")
|
||||
}
|
||||
|
||||
pub(crate) fn leave_multicast_v6(
|
||||
&self,
|
||||
_multiaddr: &Ipv6Addr,
|
||||
_interface: u32,
|
||||
) -> io::Result<()> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::leave_multicast_v6()")
|
||||
}
|
||||
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::take_error()")
|
||||
}
|
||||
|
||||
pub(crate) fn accept(&self) -> io::Result<(SocketFileDesc, SocketAddr)> {
|
||||
let (raw, remote) = rt::socket::accept_ip(self.as_raw_fd())?;
|
||||
let fd = unsafe { Self::from_raw_fd(raw) };
|
||||
Ok((fd, remote))
|
||||
}
|
||||
|
||||
pub(crate) fn recv_from(&self, buffer: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
||||
Ok(rt::socket::receive_from_ip(self.as_raw_fd(), buffer)?)
|
||||
}
|
||||
|
||||
pub(crate) fn recv(&self, buffer: &mut [u8]) -> io::Result<usize> {
|
||||
Ok(rt::socket::receive(self.as_raw_fd(), buffer)?)
|
||||
}
|
||||
|
||||
pub(crate) fn recv_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::recv_buf()")
|
||||
}
|
||||
|
||||
pub(crate) fn recv_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::recv_vectored()")
|
||||
}
|
||||
|
||||
pub(crate) fn peek(&self, _buffer: &mut [u8]) -> io::Result<usize> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::peek()")
|
||||
}
|
||||
|
||||
pub(crate) fn peek_from(&self, _buffer: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::peek_from()")
|
||||
}
|
||||
|
||||
pub(crate) fn send(&self, data: &[u8]) -> io::Result<usize> {
|
||||
Ok(rt::socket::send(self.as_raw_fd(), data)?)
|
||||
}
|
||||
|
||||
pub(crate) fn send_to(&self, data: &[u8], dst: &SocketAddr) -> io::Result<usize> {
|
||||
Ok(rt::socket::send_to_ip(self.as_raw_fd(), data, dst)?)
|
||||
}
|
||||
|
||||
pub(crate) fn send_vectored(&self, _data: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::send_vectored()")
|
||||
}
|
||||
|
||||
pub(crate) fn shutdown(&self, _how: Shutdown) -> io::Result<()> {
|
||||
todo!("sys::fd::yggdrasil::socket::SocketFileDesc::shutdown()")
|
||||
}
|
||||
|
||||
pub(crate) fn try_clone(&self) -> io::Result<Self> {
|
||||
let fd = unsafe { syscall::clone_fd(self.as_raw_fd(), None) }?;
|
||||
Ok(unsafe { Self::from_raw_fd(fd) })
|
||||
}
|
||||
}
|
||||
|
||||
impl AsFd for SocketFileDesc {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
self.fd.as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for SocketFileDesc {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.fd.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for SocketFileDesc {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for SocketFileDesc {
|
||||
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
|
||||
unsafe { Self { fd: FromRawFd::from_raw_fd(raw_fd) } }
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<OwnedFd> for SocketFileDesc {
|
||||
fn into_inner(self) -> OwnedFd {
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<OwnedFd> for SocketFileDesc {
|
||||
fn as_inner(&self) -> &OwnedFd {
|
||||
&self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<OwnedFd> for SocketFileDesc {
|
||||
fn from_inner(fd: OwnedFd) -> Self {
|
||||
Self { fd }
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,11 @@ cfg_select! {
|
||||
mod vexos;
|
||||
use vexos as imp;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
use yggdrasil as imp;
|
||||
pub(crate) use imp::get_metadata_inner;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
use unsupported as imp;
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
use yggdrasil_rt::io::{
|
||||
FileAttr as OsFileAttr, FileMetadataUpdate, FileMetadataUpdateMode, FileMode as OsFileMode,
|
||||
FileType as OsFileType,
|
||||
};
|
||||
use yggdrasil_rt::time::SystemTime as RtSystemTime;
|
||||
|
||||
use crate::hash::Hash;
|
||||
use crate::os::fd::RawFd;
|
||||
use crate::path::Path;
|
||||
use crate::sys::run_with_path_str;
|
||||
use crate::sys::time::SystemTime;
|
||||
use crate::{fmt, io};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub struct FileAttr(pub(super) OsFileAttr);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct FilePermissions(pub(super) OsFileMode);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct FileType(pub(super) OsFileType);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct FileTimes {
|
||||
pub(crate) atime: Option<RtSystemTime>,
|
||||
pub(crate) mtime: Option<RtSystemTime>,
|
||||
}
|
||||
|
||||
impl FileAttr {
|
||||
pub fn size(&self) -> u64 {
|
||||
self.0.size
|
||||
}
|
||||
|
||||
pub fn perm(&self) -> FilePermissions {
|
||||
FilePermissions(self.0.mode)
|
||||
}
|
||||
|
||||
pub fn file_type(&self) -> FileType {
|
||||
FileType(self.0.ty)
|
||||
}
|
||||
|
||||
pub fn mode_ext(&self) -> OsFileMode {
|
||||
self.0.mode
|
||||
}
|
||||
|
||||
pub fn inode(&self) -> Option<u32> {
|
||||
self.0.inode
|
||||
}
|
||||
|
||||
pub fn block_count(&self) -> u64 {
|
||||
self.0.block_count
|
||||
}
|
||||
|
||||
pub fn block_size(&self) -> u64 {
|
||||
self.0.block_size
|
||||
}
|
||||
|
||||
pub fn modified(&self) -> io::Result<SystemTime> {
|
||||
let time = SystemTime(self.0.mtime);
|
||||
Ok(time)
|
||||
}
|
||||
|
||||
pub fn accessed(&self) -> io::Result<SystemTime> {
|
||||
let time = SystemTime(self.0.atime);
|
||||
Ok(time)
|
||||
}
|
||||
|
||||
pub fn created(&self) -> io::Result<SystemTime> {
|
||||
let time = SystemTime(self.0.ctime);
|
||||
Ok(time)
|
||||
}
|
||||
}
|
||||
|
||||
impl FilePermissions {
|
||||
pub fn readonly(&self) -> bool {
|
||||
!self.0.contains_any(
|
||||
OsFileMode::USER_WRITE | OsFileMode::GROUP_WRITE | OsFileMode::OTHER_WRITE,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_readonly(&mut self, readonly: bool) {
|
||||
if readonly {
|
||||
self.0 &= !(OsFileMode::USER_WRITE | OsFileMode::GROUP_WRITE | OsFileMode::OTHER_WRITE);
|
||||
} else {
|
||||
self.0 |= OsFileMode::USER_WRITE | OsFileMode::GROUP_WRITE | OsFileMode::OTHER_WRITE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FilePermissions {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.0.bits(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileType {
|
||||
pub fn is_dir(&self) -> bool {
|
||||
self.0 == OsFileType::Directory
|
||||
}
|
||||
|
||||
pub fn is_file(&self) -> bool {
|
||||
self.0 == OsFileType::File
|
||||
}
|
||||
|
||||
pub fn is_symlink(&self) -> bool {
|
||||
self.0 == OsFileType::Symlink
|
||||
}
|
||||
|
||||
pub fn is_char_device(&self) -> bool {
|
||||
self.0 == OsFileType::Char
|
||||
}
|
||||
|
||||
pub fn is_block_device(&self) -> bool {
|
||||
self.0 == OsFileType::Block
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FileType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl FileTimes {
|
||||
pub fn set_accessed(&mut self, t: SystemTime) {
|
||||
self.atime = Some(t.0);
|
||||
}
|
||||
|
||||
pub fn set_modified(&mut self, t: SystemTime) {
|
||||
self.mtime = Some(t.0);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_metadata_inner(
|
||||
at: Option<RawFd>,
|
||||
path: &str,
|
||||
follow: bool,
|
||||
) -> io::Result<FileAttr> {
|
||||
let mut metadata = crate::mem::MaybeUninit::uninit();
|
||||
unsafe { yggdrasil_rt::sys::get_metadata(at, path, &mut metadata, follow) }?;
|
||||
Ok(unsafe { FileAttr(metadata.assume_init()) })
|
||||
}
|
||||
|
||||
pub fn stat(path: &Path) -> io::Result<FileAttr> {
|
||||
run_with_path_str(path, |path_str| get_metadata_inner(None, path_str, true))
|
||||
}
|
||||
|
||||
pub fn lstat(path: &Path) -> io::Result<FileAttr> {
|
||||
run_with_path_str(path, |path_str| get_metadata_inner(None, path_str, false))
|
||||
}
|
||||
|
||||
pub fn set_perm(path: &Path, perm: FilePermissions) -> io::Result<()> {
|
||||
run_with_path_str(path, |path_str| {
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::update_metadata(
|
||||
None,
|
||||
path_str,
|
||||
&FileMetadataUpdate::Permissions(FileMetadataUpdateMode::Set(perm.0)),
|
||||
)
|
||||
}
|
||||
.map_err(io::Error::from)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> {
|
||||
todo!("sys::fs::yggdrasil::set_times()")
|
||||
}
|
||||
|
||||
pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> {
|
||||
todo!("sys::fs::yggdrasil::set_times_nofollow()")
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
use yggdrasil_rt::io::{DirectoryEntry as OsDirectoryEntry, FileMode as OsFileMode};
|
||||
|
||||
use super::{FileAttr, FileType, get_metadata_inner};
|
||||
use crate::ffi::OsString;
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::os::fd::{AsRawFd, FromRawFd};
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::str::FromStr;
|
||||
use crate::sys::fd::FileDesc;
|
||||
use crate::sys::run_with_path_str;
|
||||
use crate::{fmt, io};
|
||||
|
||||
const BUFFER_SIZE: usize = 8;
|
||||
|
||||
pub struct DirEntry {
|
||||
filename: OsString,
|
||||
path: PathBuf,
|
||||
ty: FileType,
|
||||
}
|
||||
|
||||
pub struct ReadDir {
|
||||
fd: FileDesc,
|
||||
path: PathBuf,
|
||||
// TODO fetch more entries at a time
|
||||
buffer: [MaybeUninit<OsDirectoryEntry>; BUFFER_SIZE],
|
||||
buffer_position: usize,
|
||||
buffer_len: usize,
|
||||
eof: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DirBuilder {
|
||||
mode: OsFileMode,
|
||||
}
|
||||
|
||||
impl ReadDir {
|
||||
fn open(path: &Path) -> io::Result<Self> {
|
||||
let path_buf = PathBuf::from(path);
|
||||
let path_str = path.to_str().unwrap();
|
||||
let fd = unsafe { yggdrasil_rt::sys::open_directory(None, path_str) }?;
|
||||
Ok(ReadDir {
|
||||
fd: unsafe { FileDesc::from_raw_fd(fd) },
|
||||
buffer: [MaybeUninit::uninit(); BUFFER_SIZE],
|
||||
buffer_position: 0,
|
||||
buffer_len: 0,
|
||||
path: path_buf,
|
||||
eof: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn fill_buffer(&mut self) -> io::Result<()> {
|
||||
// If eof, don't attempt to load anything
|
||||
// If pos != len, still have some entries
|
||||
if self.eof || self.buffer_position != self.buffer_len {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.buffer_position = 0;
|
||||
self.buffer_len = unsafe {
|
||||
yggdrasil_rt::sys::read_directory_entries(self.fd.as_raw_fd(), &mut self.buffer)
|
||||
}?;
|
||||
|
||||
if self.buffer_len == 0 {
|
||||
self.eof = true;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for ReadDir {
|
||||
type Item = io::Result<DirEntry>;
|
||||
|
||||
fn next(&mut self) -> Option<io::Result<DirEntry>> {
|
||||
loop {
|
||||
if let Err(e) = self.fill_buffer() {
|
||||
break Some(Err(e));
|
||||
}
|
||||
|
||||
if self.eof {
|
||||
return None;
|
||||
}
|
||||
|
||||
assert_ne!(self.buffer_position, self.buffer_len);
|
||||
|
||||
let entry = unsafe { self.buffer[self.buffer_position].assume_init_ref() };
|
||||
self.buffer_position += 1;
|
||||
|
||||
break Some(DirEntry::from_raw(self.path.clone(), entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ReadDir {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&*self.path, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl DirEntry {
|
||||
fn from_raw(parent: PathBuf, raw: &OsDirectoryEntry) -> io::Result<Self> {
|
||||
let filename = OsString::from_str(raw.name.as_ref()).unwrap();
|
||||
let path = parent.join(filename.clone());
|
||||
let ty = match raw.ty {
|
||||
Some(ty) => FileType(ty),
|
||||
None => {
|
||||
let metadata = run_with_path_str(path.as_ref(), |path_str| {
|
||||
get_metadata_inner(None, path_str, false)
|
||||
})?;
|
||||
|
||||
metadata.file_type()
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self { path, filename, ty })
|
||||
}
|
||||
|
||||
pub fn path(&self) -> PathBuf {
|
||||
self.path.clone()
|
||||
}
|
||||
|
||||
pub fn file_name(&self) -> OsString {
|
||||
self.filename.clone()
|
||||
}
|
||||
|
||||
pub fn metadata(&self) -> io::Result<FileAttr> {
|
||||
run_with_path_str(self.path.as_ref(), |path_str| get_metadata_inner(None, path_str, false))
|
||||
}
|
||||
|
||||
pub fn file_type(&self) -> io::Result<FileType> {
|
||||
Ok(self.ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl DirBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self { mode: OsFileMode::default_dir() }
|
||||
}
|
||||
|
||||
pub fn mkdir(&self, path: &Path) -> io::Result<()> {
|
||||
run_with_path_str(path, |path_str| {
|
||||
unsafe { yggdrasil_rt::sys::create_directory(None, path_str, self.mode) }
|
||||
.map_err(io::Error::from)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn readdir(path: &Path) -> io::Result<ReadDir> {
|
||||
ReadDir::open(path)
|
||||
}
|
||||
|
||||
pub fn rmdir(path: &Path) -> io::Result<()> {
|
||||
run_with_path_str(path, |path_str| {
|
||||
yggdrasil_rt::io::remove_directory(None, path_str).map_err(io::Error::from)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
|
||||
run_with_path_str(path, |path_str| {
|
||||
yggdrasil_rt::io::remove_directory_recursive(None, path_str).map_err(io::Error::from)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
use yggdrasil_rt::io::{
|
||||
FileMetadataUpdate, FileMetadataUpdateMode, FileMode as OsFileMode, FileTimesUpdate,
|
||||
OpenOptions as OsOpenOptions,
|
||||
};
|
||||
|
||||
use super::{FileAttr, FilePermissions, FileTimes};
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
|
||||
use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
|
||||
use crate::path::Path;
|
||||
use crate::sys::fd::FileDesc;
|
||||
use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct File(FileDesc);
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct OpenOptions {
|
||||
pub(crate) options: OsOpenOptions,
|
||||
pub(crate) mode: OsFileMode,
|
||||
}
|
||||
|
||||
impl OpenOptions {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn read(&mut self, read: bool) {
|
||||
if read {
|
||||
self.options |= OsOpenOptions::READ;
|
||||
} else {
|
||||
self.options &= !OsOpenOptions::READ;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&mut self, write: bool) {
|
||||
if write {
|
||||
self.options |= OsOpenOptions::WRITE;
|
||||
} else {
|
||||
self.options &= !OsOpenOptions::WRITE;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append(&mut self, append: bool) {
|
||||
if append {
|
||||
self.options |= OsOpenOptions::APPEND;
|
||||
} else {
|
||||
self.options &= !OsOpenOptions::APPEND;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn truncate(&mut self, truncate: bool) {
|
||||
if truncate {
|
||||
self.options |= OsOpenOptions::TRUNCATE;
|
||||
} else {
|
||||
self.options &= !OsOpenOptions::TRUNCATE;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(&mut self, create: bool) {
|
||||
if create {
|
||||
self.options |= OsOpenOptions::CREATE;
|
||||
} else {
|
||||
self.options &= !OsOpenOptions::CREATE;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_new(&mut self, create_new: bool) {
|
||||
if create_new {
|
||||
self.options |= OsOpenOptions::CREATE_EXCL | OsOpenOptions::CREATE;
|
||||
} else {
|
||||
self.options &= !OsOpenOptions::CREATE_EXCL | OsOpenOptions::CREATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for OpenOptions {
|
||||
fn default() -> Self {
|
||||
Self { mode: OsFileMode::default_file(), options: OsOpenOptions::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
|
||||
let path = path.as_os_str();
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::open(None, path.to_str().unwrap(), opts.options, opts.mode)
|
||||
.map(|fd| File::from_raw_fd(fd))
|
||||
.map_err(io::Error::from)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn file_attr(&self) -> io::Result<FileAttr> {
|
||||
self.0.metadata()
|
||||
}
|
||||
|
||||
pub fn fsync(&self) -> io::Result<()> {
|
||||
self.0.fsync()
|
||||
}
|
||||
|
||||
pub fn datasync(&self) -> io::Result<()> {
|
||||
self.0.datasync()
|
||||
}
|
||||
|
||||
pub fn truncate(&self, size: u64) -> io::Result<()> {
|
||||
self.0.truncate(size)
|
||||
}
|
||||
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.read(buf)
|
||||
}
|
||||
|
||||
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.0.read_vectored(bufs)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_read_vectored(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
self.0.read_buf(cursor)
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.write(buf)
|
||||
}
|
||||
|
||||
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
self.0.write_vectored(bufs)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_write_vectored(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn lock(&self) -> io::Result<()> {
|
||||
todo!("File::lock()")
|
||||
}
|
||||
|
||||
pub fn lock_shared(&self) -> io::Result<()> {
|
||||
todo!("File::lock_shared()")
|
||||
}
|
||||
|
||||
pub fn try_lock(&self) -> Result<(), crate::fs::TryLockError> {
|
||||
todo!("File::try_lock()")
|
||||
}
|
||||
|
||||
pub fn try_lock_shared(&self) -> Result<(), crate::fs::TryLockError> {
|
||||
todo!("File::try_lock_shared()")
|
||||
}
|
||||
|
||||
pub fn unlock(&self) -> io::Result<()> {
|
||||
todo!("File::unlock()")
|
||||
}
|
||||
|
||||
pub fn flush(&self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn size(&self) -> Option<io::Result<u64>> {
|
||||
// TODO
|
||||
None
|
||||
}
|
||||
|
||||
pub fn tell(&self) -> io::Result<u64> {
|
||||
self.0.seek(SeekFrom::Current(0))
|
||||
}
|
||||
|
||||
pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
|
||||
self.0.seek(pos)
|
||||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<File> {
|
||||
self.0.try_clone().map(Self)
|
||||
}
|
||||
|
||||
pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::update_metadata(
|
||||
Some(self.as_raw_fd()),
|
||||
"",
|
||||
&FileMetadataUpdate::Permissions(FileMetadataUpdateMode::Set(perm.0)),
|
||||
)
|
||||
}
|
||||
.map_err(io::Error::from)
|
||||
}
|
||||
|
||||
pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::update_metadata(
|
||||
Some(self.as_raw_fd()),
|
||||
"",
|
||||
&FileMetadataUpdate::Times(FileTimesUpdate {
|
||||
atime: times.atime,
|
||||
mtime: times.mtime,
|
||||
ctime: None,
|
||||
}),
|
||||
)
|
||||
}
|
||||
.map_err(io::Error::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<FileDesc> for File {
|
||||
fn as_inner(&self) -> &FileDesc {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<FileDesc> for File {
|
||||
fn into_inner(self) -> FileDesc {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInnerMut<FileDesc> for File {
|
||||
fn as_inner_mut(&mut self) -> &mut FileDesc {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<FileDesc> for File {
|
||||
fn from_inner(file_desc: FileDesc) -> Self {
|
||||
Self(file_desc)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsFd for File {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
self.0.as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for File {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for File {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.0.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for File {
|
||||
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
|
||||
unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#![allow(exported_private_dependencies)]
|
||||
|
||||
use yggdrasil_rt::io::{AccessMode as OsAccessMode, Rename};
|
||||
|
||||
use crate::os::yggdrasil::fs::{MetadataExt, OpenOptionsExt};
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::sys::run_with_path_str;
|
||||
use crate::{io, os};
|
||||
|
||||
mod attr;
|
||||
mod dir;
|
||||
mod file;
|
||||
|
||||
pub(crate) use attr::get_metadata_inner;
|
||||
pub use attr::{
|
||||
FileAttr, FilePermissions, FileTimes, FileType, lstat, set_perm, set_times, set_times_nofollow,
|
||||
stat,
|
||||
};
|
||||
pub use dir::{DirBuilder, DirEntry, ReadDir, readdir, remove_dir_all, rmdir};
|
||||
pub use file::{File, OpenOptions};
|
||||
|
||||
pub use crate::sys::fs::common::Dir;
|
||||
|
||||
pub fn unlink(path: &Path) -> io::Result<()> {
|
||||
run_with_path_str(path, |path_str| {
|
||||
yggdrasil_rt::io::remove_file(None, path_str).map_err(io::Error::from)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
|
||||
let old = old.to_str().unwrap();
|
||||
let new = new.to_str().unwrap();
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::rename(&Rename {
|
||||
source_at: None,
|
||||
destination_at: None,
|
||||
source: old,
|
||||
destination: new,
|
||||
})
|
||||
}?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn exists(path: &Path) -> io::Result<bool> {
|
||||
run_with_path_str(path, |path| {
|
||||
unsafe { yggdrasil_rt::sys::check_access(None, path, OsAccessMode::empty()) }
|
||||
.map_err(io::Error::from)
|
||||
})
|
||||
.map(|_| true)
|
||||
}
|
||||
|
||||
pub fn readlink(path: &Path) -> io::Result<PathBuf> {
|
||||
// TODO PATH_MAX
|
||||
let mut buf = [0; 4096];
|
||||
let len = run_with_path_str(path, |path_str| {
|
||||
unsafe { yggdrasil_rt::sys::read_link(None, path_str, &mut buf) }.map_err(io::Error::from)
|
||||
})?;
|
||||
// TODO error handling
|
||||
let path = core::str::from_utf8(&buf[..len]).unwrap();
|
||||
Ok(PathBuf::from(path))
|
||||
}
|
||||
|
||||
pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
|
||||
os::yggdrasil::fs::symlink(original, link)
|
||||
}
|
||||
|
||||
pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
|
||||
Err(io::Error::new(io::ErrorKind::Uncategorized, "Hard links are not implemented"))
|
||||
}
|
||||
|
||||
pub fn canonicalize(path: &Path) -> io::Result<PathBuf> {
|
||||
run_with_path_str(path, |path_str| {
|
||||
yggdrasil_rt::io::canonicalize(path_str, |s| s.into()).map_err(io::Error::from)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
|
||||
let src_stat = from.metadata()?;
|
||||
let raw_mode = src_stat.mode_ext();
|
||||
let mut src = crate::fs::File::open(from)?;
|
||||
let mut dst = crate::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.create(true)
|
||||
.mode_ext(raw_mode)
|
||||
.open(to)?;
|
||||
|
||||
crate::io::copy(&mut src, &mut dst)
|
||||
}
|
||||
@@ -39,6 +39,10 @@ cfg_select! {
|
||||
mod xous;
|
||||
pub use xous::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::*;
|
||||
}
|
||||
any(
|
||||
target_os = "vexos",
|
||||
target_family = "wasm",
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
use yggdrasil_rt::Error as OsError;
|
||||
|
||||
use crate::io::{self, RawOsError};
|
||||
|
||||
pub fn errno() -> i32 {
|
||||
// Errors are not reported via errno
|
||||
0
|
||||
}
|
||||
|
||||
pub fn is_interrupted(code: i32) -> bool {
|
||||
decode_error_kind(code) == io::ErrorKind::Interrupted
|
||||
}
|
||||
|
||||
pub fn decode_error_kind(errno: i32) -> io::ErrorKind {
|
||||
let errno = errno as u32;
|
||||
match OsError::try_from(errno) {
|
||||
// I/O kinds
|
||||
Ok(OsError::DoesNotExist) | Ok(OsError::ProcessNotFound) => io::ErrorKind::NotFound,
|
||||
Ok(OsError::AlreadyExists) => io::ErrorKind::AlreadyExists,
|
||||
Ok(OsError::TimedOut) => io::ErrorKind::TimedOut,
|
||||
Ok(OsError::IsADirectory) => io::ErrorKind::IsADirectory,
|
||||
Ok(OsError::NotADirectory) => io::ErrorKind::NotADirectory,
|
||||
Ok(OsError::DirectoryNotEmpty) => io::ErrorKind::DirectoryNotEmpty,
|
||||
Ok(OsError::Interrupted) => io::ErrorKind::Interrupted,
|
||||
Ok(OsError::WouldBlock) => io::ErrorKind::WouldBlock,
|
||||
Ok(OsError::ReadOnly) => io::ErrorKind::ReadOnlyFilesystem,
|
||||
Ok(OsError::PermissionDenied) => io::ErrorKind::PermissionDenied,
|
||||
Ok(OsError::CrossDeviceLink) => io::ErrorKind::CrossesDevices,
|
||||
Ok(OsError::UnrecognizedExecutable)
|
||||
| Ok(OsError::MissingData)
|
||||
| Ok(OsError::BufferTooSmall)
|
||||
| Ok(OsError::QueueFull) => io::ErrorKind::InvalidData,
|
||||
|
||||
// Memory and general
|
||||
Ok(OsError::OutOfMemory) => io::ErrorKind::OutOfMemory,
|
||||
Ok(OsError::InvalidArgument)
|
||||
| Ok(OsError::InvalidMemoryOperation)
|
||||
| Ok(OsError::InvalidOperation)
|
||||
| Ok(OsError::UndefinedSyscall) => io::ErrorKind::InvalidInput,
|
||||
Ok(OsError::NotImplemented) => io::ErrorKind::Unsupported,
|
||||
|
||||
// Network
|
||||
Ok(OsError::HostUnreachable) => io::ErrorKind::HostUnreachable,
|
||||
Ok(OsError::NetworkUnreachable) => io::ErrorKind::NetworkUnreachable,
|
||||
Ok(OsError::ConnectionReset) => io::ErrorKind::ConnectionReset,
|
||||
Ok(OsError::ConnectionRefused) => io::ErrorKind::ConnectionRefused,
|
||||
Ok(OsError::NotConnected) => io::ErrorKind::NotConnected,
|
||||
Ok(OsError::AddrInUse) => io::ErrorKind::AddrInUse,
|
||||
|
||||
// Uncategorized
|
||||
Ok(OsError::InvalidFile) => io::ErrorKind::Uncategorized,
|
||||
Err(_) => io::ErrorKind::Uncategorized,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn error_string(errno: i32) -> String {
|
||||
crate::format!("{}", decode_error_kind(errno))
|
||||
}
|
||||
|
||||
#[allow(exported_private_dependencies)]
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl From<yggdrasil_rt::Error> for crate::io::Error {
|
||||
fn from(e: yggdrasil_rt::Error) -> Self {
|
||||
let raw_os_error = u32::from(e) as RawOsError;
|
||||
io::Error::from_raw_os_error(raw_os_error)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
use crate::os::fd::{AsFd, AsRawFd};
|
||||
|
||||
pub fn is_terminal(fd: &impl AsFd) -> bool {
|
||||
let fd = fd.as_fd();
|
||||
yggdrasil_rt::io::terminal::is_terminal(fd.as_raw_fd())
|
||||
}
|
||||
@@ -41,6 +41,10 @@ mod is_terminal {
|
||||
mod motor;
|
||||
pub use motor::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::*;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use unsupported::*;
|
||||
|
||||
@@ -29,6 +29,10 @@ cfg_select! {
|
||||
mod uefi;
|
||||
pub use uefi::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::*;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use unsupported::*;
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
use yggdrasil_rt::net::dns::{
|
||||
self, DnsClass, DnsMessage, DnsRecordData, DnsReplyCode, DnsType, UdpRequester,
|
||||
};
|
||||
|
||||
use crate::fs::File;
|
||||
use crate::io::{self, BufRead, BufReader};
|
||||
use crate::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
|
||||
use crate::os::fd::AsRawFd;
|
||||
use crate::os::yggdrasil::io::poll::PollChannel;
|
||||
use crate::os::yggdrasil::io::timer::TimerFd;
|
||||
use crate::str::FromStr;
|
||||
use crate::sys::pal::util::random;
|
||||
use crate::time::Duration;
|
||||
|
||||
const TIMEOUT: u64 = 500;
|
||||
const NAMESERVER: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 53);
|
||||
const HOSTS_PATH: &str = "/etc/hosts";
|
||||
|
||||
pub struct LookupHost {
|
||||
addresses: Vec<IpAddr>,
|
||||
port: u16,
|
||||
}
|
||||
|
||||
struct DnsRequester {
|
||||
nameserver: SocketAddr,
|
||||
|
||||
poll: PollChannel,
|
||||
|
||||
timer: TimerFd,
|
||||
socket: UdpSocket,
|
||||
}
|
||||
|
||||
impl DnsRequester {
|
||||
pub fn new(nameserver: SocketAddr) -> io::Result<Self> {
|
||||
let mut poll = PollChannel::new()?;
|
||||
let timer = TimerFd::new(false, false)?;
|
||||
let socket = UdpSocket::bind("0.0.0.0:0")?;
|
||||
|
||||
poll.add(timer.as_raw_fd())?;
|
||||
poll.add(socket.as_raw_fd())?;
|
||||
|
||||
Ok(Self { nameserver, poll, timer, socket })
|
||||
}
|
||||
}
|
||||
|
||||
impl UdpRequester for DnsRequester {
|
||||
type Error = io::Error;
|
||||
|
||||
fn send_message(&mut self, message: &[u8]) -> io::Result<()> {
|
||||
self.socket.send_to(message, &self.nameserver)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn receive_message<F: Fn(&[u8]) -> Option<DnsMessage>>(
|
||||
&mut self,
|
||||
map: F,
|
||||
) -> io::Result<DnsMessage> {
|
||||
let mut buffer = [0; 2048];
|
||||
|
||||
self.timer.start(Duration::from_millis(TIMEOUT))?;
|
||||
|
||||
loop {
|
||||
let (poll_fd, result) = self.poll.wait(None, true)?.unwrap();
|
||||
result?;
|
||||
|
||||
match poll_fd {
|
||||
fd if fd == self.socket.as_raw_fd() => {
|
||||
let (len, _) = self.socket.recv_from(&mut buffer)?;
|
||||
|
||||
if let Some(message) = map(&buffer[..len]) {
|
||||
return Ok(message);
|
||||
}
|
||||
}
|
||||
fd if fd == self.timer.as_raw_fd() => {
|
||||
return Err(io::Error::new(io::ErrorKind::TimedOut, "DNS query timed out"));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl LookupHost {
|
||||
// pub fn port(&self) -> u16 {
|
||||
// self.port
|
||||
// }
|
||||
// }
|
||||
|
||||
impl Iterator for LookupHost {
|
||||
type Item = SocketAddr;
|
||||
|
||||
fn next(&mut self) -> Option<SocketAddr> {
|
||||
let ip = self.addresses.pop()?;
|
||||
Some(SocketAddr::new(ip, self.port))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for LookupHost {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from(s: &str) -> io::Result<Self> {
|
||||
use crate::str::FromStr;
|
||||
|
||||
let (hostname, port) = s
|
||||
.rsplit_once(':')
|
||||
.ok_or(io::Error::new(io::ErrorKind::InvalidData, "Invalid host:port combination"))?;
|
||||
let port =
|
||||
u16::from_str(port).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
|
||||
Self::try_from((hostname, port))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from((hostname, port): (&'a str, u16)) -> io::Result<Self> {
|
||||
if let Ok(addresses) = get_addresses_from_hosts(hostname) {
|
||||
if !addresses.is_empty() {
|
||||
return Ok(Self { addresses, port });
|
||||
}
|
||||
}
|
||||
|
||||
let addresses = get_addresses_from_dns(hostname)?;
|
||||
|
||||
Ok(Self { addresses, port })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lookup_host(query: &str, port: u16) -> io::Result<LookupHost> {
|
||||
LookupHost::try_from((query, port))
|
||||
}
|
||||
|
||||
fn get_addresses_from_hosts(hostname: &str) -> io::Result<Vec<IpAddr>> {
|
||||
let reader = BufReader::new(File::open(HOSTS_PATH)?);
|
||||
let mut addresses = vec![];
|
||||
for line in reader.lines() {
|
||||
let line = line?;
|
||||
let line = line.trim();
|
||||
if line.starts_with('#') {
|
||||
continue;
|
||||
}
|
||||
let Some((address, host)) = line.split_once(' ') else {
|
||||
continue;
|
||||
};
|
||||
let address = address.trim();
|
||||
let host = host.trim();
|
||||
let Ok(address) = IpAddr::from_str(address) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if host == hostname {
|
||||
addresses.push(address);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(addresses)
|
||||
}
|
||||
|
||||
fn get_addresses_from_dns(hostname: &str) -> io::Result<Vec<IpAddr>> {
|
||||
let xid = random();
|
||||
let cookie = random();
|
||||
let mut addresses = vec![];
|
||||
let mut requester = DnsRequester::new(NAMESERVER)?;
|
||||
let message = dns::perform_query(&mut requester, hostname, DnsType::A, xid, cookie)?;
|
||||
|
||||
if message.reply_code != DnsReplyCode::NO_ERROR {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "DNS server returned error"));
|
||||
}
|
||||
|
||||
for answer in message.answers {
|
||||
let Some(name) = answer.name.0.as_ref() else {
|
||||
continue;
|
||||
};
|
||||
let name = name.trim_end_matches('.');
|
||||
if name != hostname {
|
||||
continue;
|
||||
}
|
||||
|
||||
match (answer.ty, answer.class, &answer.rdata) {
|
||||
(DnsType::A, DnsClass::IN, DnsRecordData::A(address)) => {
|
||||
addresses.push(IpAddr::V4(u32::from(*address).into()));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(addresses)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#![allow(exported_private_dependencies)]
|
||||
|
||||
mod lookup_host;
|
||||
mod tcp_listener;
|
||||
mod tcp_stream;
|
||||
mod udp_socket;
|
||||
|
||||
pub use lookup_host::lookup_host;
|
||||
pub use tcp_listener::TcpListener;
|
||||
pub use tcp_stream::TcpStream;
|
||||
pub use udp_socket::UdpSocket;
|
||||
@@ -0,0 +1,100 @@
|
||||
use yggdrasil_rt::net as rt;
|
||||
|
||||
use super::TcpStream;
|
||||
use crate::io;
|
||||
use crate::net::{SocketAddr, ToSocketAddrs};
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
use crate::sys::fd::SocketFileDesc;
|
||||
use crate::sys::net::connection::each_addr;
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TcpListener(SocketFileDesc);
|
||||
|
||||
impl TcpListener {
|
||||
fn try_bind(addr: &SocketAddr) -> io::Result<TcpListener> {
|
||||
let raw = rt::bind_tcp(addr)?;
|
||||
let fd = unsafe { SocketFileDesc::from_raw_fd(raw) };
|
||||
Ok(Self(fd))
|
||||
}
|
||||
|
||||
// pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
|
||||
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
|
||||
each_addr(addr, Self::try_bind)
|
||||
}
|
||||
|
||||
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.0.local_addr()
|
||||
}
|
||||
|
||||
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
|
||||
let (fd, remote) = self.0.accept()?;
|
||||
let stream = TcpStream::from_inner(fd);
|
||||
Ok((stream, remote))
|
||||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<TcpListener> {
|
||||
self.0.try_clone().map(Self)
|
||||
}
|
||||
|
||||
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
|
||||
self.0.set_ttl(ttl)
|
||||
}
|
||||
|
||||
pub fn ttl(&self) -> io::Result<u32> {
|
||||
self.0.ttl()
|
||||
}
|
||||
|
||||
pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
|
||||
self.0.set_only_v6(only_v6)
|
||||
}
|
||||
|
||||
pub fn only_v6(&self) -> io::Result<bool> {
|
||||
self.0.only_v6()
|
||||
}
|
||||
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
self.0.take_error()
|
||||
}
|
||||
|
||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
self.0.set_nonblocking(nonblocking)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<SocketFileDesc> for TcpListener {
|
||||
fn from_inner(fd: SocketFileDesc) -> Self {
|
||||
Self(fd)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<SocketFileDesc> for TcpListener {
|
||||
fn into_inner(self) -> SocketFileDesc {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<SocketFileDesc> for TcpListener {
|
||||
fn as_inner(&self) -> &SocketFileDesc {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for TcpListener {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
Self(SocketFileDesc::from_raw_fd(fd))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for TcpListener {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl AsRawFd for crate::net::TcpListener {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.as_inner().as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
use yggdrasil_rt::net as rt;
|
||||
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
|
||||
use crate::net::{Shutdown, SocketAddr, ToSocketAddrs};
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
use crate::sys::fd::SocketFileDesc;
|
||||
use crate::sys::net::connection::each_addr;
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
use crate::time::Duration;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TcpStream(SocketFileDesc);
|
||||
|
||||
impl TcpStream {
|
||||
fn connect_inner(remote: &SocketAddr, timeout: Option<Duration>) -> io::Result<TcpStream> {
|
||||
let fd = rt::connect_tcp(remote, timeout)?;
|
||||
let fd = unsafe { SocketFileDesc::from_raw_fd(fd) };
|
||||
Ok(Self(fd))
|
||||
}
|
||||
|
||||
// pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
|
||||
pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
|
||||
each_addr(addr, |addr| Self::connect_inner(addr, None))
|
||||
}
|
||||
|
||||
pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
|
||||
Self::connect_inner(addr, Some(timeout))
|
||||
}
|
||||
|
||||
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||
self.0.set_read_timeout(dur)
|
||||
}
|
||||
|
||||
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||
self.0.set_write_timeout(dur)
|
||||
}
|
||||
|
||||
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
self.0.read_timeout()
|
||||
}
|
||||
|
||||
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
self.0.write_timeout()
|
||||
}
|
||||
|
||||
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.peek(buf)
|
||||
}
|
||||
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.recv(buf)
|
||||
}
|
||||
|
||||
pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
self.0.recv_buf(buf)
|
||||
}
|
||||
|
||||
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.0.recv_vectored(bufs)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_read_vectored(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.send(buf)
|
||||
}
|
||||
|
||||
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
self.0.send_vectored(bufs)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_write_vectored(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.0.peer_addr()
|
||||
}
|
||||
|
||||
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.0.local_addr()
|
||||
}
|
||||
|
||||
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
|
||||
self.0.shutdown(how)
|
||||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<TcpStream> {
|
||||
self.0.try_clone().map(Self)
|
||||
}
|
||||
|
||||
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
|
||||
self.0.set_linger(linger)
|
||||
}
|
||||
|
||||
pub fn linger(&self) -> io::Result<Option<Duration>> {
|
||||
self.0.linger()
|
||||
}
|
||||
|
||||
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
|
||||
self.0.set_nodelay(nodelay)
|
||||
}
|
||||
|
||||
pub fn nodelay(&self) -> io::Result<bool> {
|
||||
self.0.nodelay()
|
||||
}
|
||||
|
||||
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
|
||||
self.0.set_ttl(ttl)
|
||||
}
|
||||
|
||||
pub fn ttl(&self) -> io::Result<u32> {
|
||||
self.0.ttl()
|
||||
}
|
||||
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
self.0.take_error()
|
||||
}
|
||||
|
||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
self.0.set_nonblocking(nonblocking)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<SocketFileDesc> for TcpStream {
|
||||
fn from_inner(fd: SocketFileDesc) -> Self {
|
||||
Self(fd)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<SocketFileDesc> for TcpStream {
|
||||
fn into_inner(self) -> SocketFileDesc {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<SocketFileDesc> for TcpStream {
|
||||
fn as_inner(&self) -> &SocketFileDesc {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for TcpStream {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
Self(SocketFileDesc::from_raw_fd(fd))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for TcpStream {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl AsRawFd for crate::net::TcpStream {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.as_inner().as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
use yggdrasil_rt::net as rt;
|
||||
|
||||
use crate::io;
|
||||
use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
use crate::sys::fd::SocketFileDesc;
|
||||
use crate::sys::net::connection::each_addr;
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
use crate::time::Duration;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UdpSocket(SocketFileDesc);
|
||||
|
||||
impl UdpSocket {
|
||||
fn try_bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
|
||||
let raw = rt::bind_udp(addr)?;
|
||||
let inner = unsafe { SocketFileDesc::from_raw_fd(raw) };
|
||||
Ok(Self(inner))
|
||||
}
|
||||
|
||||
// Should succeed on first call
|
||||
fn try_connect(&self, addr: &SocketAddr) -> io::Result<()> {
|
||||
rt::connect_udp(self.as_raw_fd(), addr)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
|
||||
each_addr(addr, Self::try_bind)
|
||||
}
|
||||
|
||||
pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
|
||||
each_addr(addr, |addr| self.try_connect(addr))
|
||||
}
|
||||
|
||||
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.0.peer_addr()
|
||||
}
|
||||
|
||||
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.0.local_addr()
|
||||
}
|
||||
|
||||
pub fn recv(&self, buffer: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.recv(buffer)
|
||||
}
|
||||
|
||||
pub fn recv_from(&self, buffer: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
||||
self.0.recv_from(buffer)
|
||||
}
|
||||
|
||||
pub fn send(&self, buffer: &[u8]) -> io::Result<usize> {
|
||||
self.0.send(buffer)
|
||||
}
|
||||
|
||||
pub fn send_to(&self, buffer: &[u8], dst: &SocketAddr) -> io::Result<usize> {
|
||||
self.0.send_to(buffer, dst)
|
||||
}
|
||||
|
||||
pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.peek(buf)
|
||||
}
|
||||
|
||||
pub fn peek_from(&self, buffer: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
|
||||
self.0.peek_from(buffer)
|
||||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<UdpSocket> {
|
||||
self.0.try_clone().map(Self)
|
||||
}
|
||||
|
||||
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||
self.0.set_read_timeout(dur)
|
||||
}
|
||||
|
||||
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
self.0.read_timeout()
|
||||
}
|
||||
|
||||
pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
|
||||
self.0.set_write_timeout(dur)
|
||||
}
|
||||
|
||||
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
self.0.write_timeout()
|
||||
}
|
||||
|
||||
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
|
||||
self.0.set_ttl(ttl)
|
||||
}
|
||||
|
||||
pub fn ttl(&self) -> io::Result<u32> {
|
||||
self.0.ttl()
|
||||
}
|
||||
|
||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
self.0.set_nonblocking(nonblocking)
|
||||
}
|
||||
|
||||
pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
|
||||
self.0.set_broadcast(broadcast)
|
||||
}
|
||||
|
||||
pub fn broadcast(&self) -> io::Result<bool> {
|
||||
self.0.broadcast()
|
||||
}
|
||||
|
||||
pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
|
||||
self.0.set_multicast_loop_v4(loop_v4)
|
||||
}
|
||||
|
||||
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
|
||||
self.0.multicast_loop_v4()
|
||||
}
|
||||
|
||||
pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
|
||||
self.0.set_multicast_ttl_v4(ttl)
|
||||
}
|
||||
|
||||
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
|
||||
self.0.multicast_ttl_v4()
|
||||
}
|
||||
|
||||
pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
|
||||
self.0.set_multicast_loop_v6(loop_v6)
|
||||
}
|
||||
|
||||
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
|
||||
self.0.multicast_loop_v6()
|
||||
}
|
||||
|
||||
pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
|
||||
self.0.join_multicast_v6(multiaddr, interface)
|
||||
}
|
||||
|
||||
pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
|
||||
self.0.join_multicast_v4(multiaddr, interface)
|
||||
}
|
||||
|
||||
pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
|
||||
self.0.leave_multicast_v6(multiaddr, interface)
|
||||
}
|
||||
|
||||
pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
|
||||
self.0.leave_multicast_v4(multiaddr, interface)
|
||||
}
|
||||
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
self.0.take_error()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<SocketFileDesc> for UdpSocket {
|
||||
fn from_inner(fd: SocketFileDesc) -> Self {
|
||||
Self(fd)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<SocketFileDesc> for UdpSocket {
|
||||
fn into_inner(self) -> SocketFileDesc {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<SocketFileDesc> for UdpSocket {
|
||||
fn as_inner(&self) -> &SocketFileDesc {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for UdpSocket {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
Self(SocketFileDesc::from_raw_fd(fd))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for UdpSocket {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl AsRawFd for crate::net::UdpSocket {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.as_inner().as_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,10 @@ cfg_select! {
|
||||
mod windows;
|
||||
pub use windows::hostname;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::hostname;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use unsupported::hostname;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
use crate::ffi::OsString;
|
||||
use crate::io::{Error, Result};
|
||||
|
||||
pub fn hostname() -> Result<OsString> {
|
||||
Err(Error::UNSUPPORTED_PLATFORM)
|
||||
}
|
||||
@@ -60,6 +60,10 @@ cfg_select! {
|
||||
mod zkvm;
|
||||
pub use self::zkvm::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use self::yggdrasil::*;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use self::unsupported::*;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// SAFETY: must be called only once during runtime initialization.
|
||||
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
|
||||
pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
|
||||
|
||||
// SAFETY: must be called only once during runtime cleanup.
|
||||
// NOTE: this is not guaranteed to run, for example when the program aborts.
|
||||
pub unsafe fn cleanup() {}
|
||||
|
||||
pub fn abort_internal() -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
use yggdrasil_rt::process::{ExitCode as OsExitCode, ProgramArgumentInner};
|
||||
|
||||
use crate::sys::{args, env, signal, thread};
|
||||
|
||||
unsafe fn init_kernel_arg(program_arg: usize) {
|
||||
unsafe {
|
||||
let program_arg = crate::ptr::with_exposed_provenance::<ProgramArgumentInner>(program_arg);
|
||||
let Some(program_arg) = program_arg.as_ref() else {
|
||||
yggdrasil_rt::debug_trace!(Error, "Kernel provided NULL argument");
|
||||
yggdrasil_rt::sys::exit_process(OsExitCode::Exited(1));
|
||||
};
|
||||
|
||||
// Setup TLS as soon as possible
|
||||
thread::init(program_arg.auxv());
|
||||
|
||||
// Setup real binary from auxv
|
||||
crate::os::yggdrasil::set_real_program(program_arg);
|
||||
|
||||
args::imp::init(program_arg);
|
||||
env::imp::init(program_arg);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn __rust_start(program_arg: usize, main_ptr: usize) -> ! {
|
||||
unsafe { init_kernel_arg(program_arg) };
|
||||
|
||||
// Initialize signals
|
||||
signal::init(true);
|
||||
|
||||
if main_ptr != 0 {
|
||||
let main: unsafe extern "C" fn(isize, *const *const u8) -> i32 =
|
||||
unsafe { core::mem::transmute(main_ptr) };
|
||||
let result = unsafe { main(0, core::ptr::null()) };
|
||||
unsafe { yggdrasil_rt::sys::exit_process(OsExitCode::Exited(result)) };
|
||||
}
|
||||
loop {}
|
||||
// let main_ptr = (main as *const ()).addr();
|
||||
// if main_ptr != 0 {
|
||||
// let result = unsafe { main(0, null()) };
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
use yggdrasil_rt::process::MutexOperation;
|
||||
use yggdrasil_rt::sys;
|
||||
|
||||
use crate::sync::atomic::Atomic;
|
||||
use crate::time::Duration;
|
||||
|
||||
pub type Primitive = u32;
|
||||
pub type Futex = Atomic<Primitive>;
|
||||
pub type SmallPrimitive = u32;
|
||||
pub type SmallFutex = Atomic<SmallPrimitive>;
|
||||
|
||||
pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>) -> bool {
|
||||
unsafe { sys::mutex(futex, &MutexOperation::WaitWhileEqual(expected, timeout)).is_ok() }
|
||||
}
|
||||
|
||||
pub fn futex_wake(futex: &Atomic<u32>) -> bool {
|
||||
unsafe { sys::mutex(futex, &MutexOperation::Wake(1)).ok() };
|
||||
true
|
||||
}
|
||||
|
||||
pub fn futex_wake_all(futex: &Atomic<u32>) {
|
||||
unsafe { sys::mutex(futex, &MutexOperation::Wake(u32::MAX)).ok() };
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
pub mod futex;
|
||||
pub mod os;
|
||||
pub mod signal;
|
||||
pub mod time;
|
||||
pub mod util;
|
||||
|
||||
mod common;
|
||||
mod entry;
|
||||
mod path;
|
||||
|
||||
pub use common::*;
|
||||
pub use path::*;
|
||||
@@ -0,0 +1,108 @@
|
||||
use yggdrasil_rt::process::ExitCode as OsExitCode;
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::error::Error as StdError;
|
||||
use crate::ffi::{OsStr, OsString};
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::sys::{AsInner, FromInner, os_str, run_with_path_str};
|
||||
use crate::{fmt, io, iter, mem, slice};
|
||||
|
||||
pub struct SplitPaths<'a> {
|
||||
iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>, fn(&'a [u8]) -> PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct JoinPathsError;
|
||||
|
||||
impl<'a> Iterator for SplitPaths<'a> {
|
||||
type Item = PathBuf;
|
||||
|
||||
fn next(&mut self) -> Option<PathBuf> {
|
||||
self.iter.next()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for JoinPathsError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "path segment contains separator `/`")
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for JoinPathsError {
|
||||
#[allow(deprecated)]
|
||||
fn description(&self) -> &str {
|
||||
"failed to join paths"
|
||||
}
|
||||
}
|
||||
|
||||
pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
|
||||
fn bytes_to_path(b: &[u8]) -> PathBuf {
|
||||
PathBuf::from(unsafe { mem::transmute::<_, &OsStr>(b) })
|
||||
}
|
||||
fn is_separator(b: &u8) -> bool {
|
||||
*b == b'/'
|
||||
}
|
||||
let unparsed = &unparsed.as_inner().inner;
|
||||
SplitPaths {
|
||||
iter: unparsed
|
||||
.split(is_separator as fn(&u8) -> bool)
|
||||
.map(bytes_to_path as fn(&[u8]) -> PathBuf),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: AsRef<OsStr>,
|
||||
{
|
||||
let mut joined = Vec::new();
|
||||
|
||||
for (i, path) in paths.enumerate() {
|
||||
let path = &path.as_ref().as_inner().inner;
|
||||
if i > 0 {
|
||||
joined.push(b'/')
|
||||
}
|
||||
if path.contains(&b'/') {
|
||||
return Err(JoinPathsError);
|
||||
}
|
||||
joined.extend_from_slice(path);
|
||||
}
|
||||
Ok(FromInner::from_inner(os_str::Buf { inner: joined }))
|
||||
}
|
||||
|
||||
pub fn current_exe() -> io::Result<PathBuf> {
|
||||
Ok(yggdrasil_rt::io::current_exe(|s| s.into())?)
|
||||
}
|
||||
|
||||
pub fn home_dir() -> Option<PathBuf> {
|
||||
yggdrasil_rt::io::home_directory(|s| s.into()).ok()
|
||||
}
|
||||
|
||||
pub fn temp_dir() -> PathBuf {
|
||||
// TODO prefix by pid
|
||||
let mut template = *b"/tmp/dXXXXXXXXX";
|
||||
yggdrasil_rt::io::make_temp_directory(&mut template)
|
||||
.expect("Could not set up a temporary directory");
|
||||
PathBuf::from(core::str::from_utf8(&template).unwrap())
|
||||
}
|
||||
|
||||
pub fn getcwd() -> io::Result<PathBuf> {
|
||||
Ok(yggdrasil_rt::io::current_directory(|s| s.into())?)
|
||||
}
|
||||
|
||||
pub fn chdir(path: &Path) -> io::Result<()> {
|
||||
run_with_path_str(path, |p| yggdrasil_rt::io::set_current_directory(p).map_err(io::Error::from))
|
||||
}
|
||||
|
||||
pub fn exit(code: i32) -> ! {
|
||||
let code = OsExitCode::Exited(code);
|
||||
unsafe { syscall::exit_process(code) }
|
||||
}
|
||||
|
||||
pub fn getpid() -> u32 {
|
||||
unsafe { syscall::get_pid() }.into_raw()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
use crate::path::Path;
|
||||
|
||||
#[inline]
|
||||
pub fn run_with_path_str<T, F: FnOnce(&str) -> T>(path: &Path, f: F) -> T {
|
||||
let path_str = path.to_str().unwrap();
|
||||
f(path_str)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#![allow(exported_private_dependencies)]
|
||||
|
||||
use yggdrasil_rt::process::Signal;
|
||||
use yggdrasil_rt::process::signal::{self as imp, SignalHandler as RtHandler};
|
||||
|
||||
use crate::os::yggdrasil::signal::SignalHandler as StdHandler;
|
||||
|
||||
const SIGNAL_STACK_SIZE: usize = 4096 * 8;
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl From<StdHandler> for RtHandler {
|
||||
fn from(std: StdHandler) -> RtHandler {
|
||||
match std {
|
||||
StdHandler::Ignore => RtHandler::Ignore,
|
||||
StdHandler::Terminate => RtHandler::Terminate,
|
||||
StdHandler::Function(function) => RtHandler::Rust(function),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl From<RtHandler> for StdHandler {
|
||||
fn from(rt: RtHandler) -> StdHandler {
|
||||
match rt {
|
||||
RtHandler::Ignore => StdHandler::Ignore,
|
||||
RtHandler::Terminate => StdHandler::Terminate,
|
||||
RtHandler::Rust(function) => StdHandler::Function(function),
|
||||
RtHandler::C(_) => unreachable!("std will never set a C signal handler"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_signal_handler(signal: Signal, handler: StdHandler) -> StdHandler {
|
||||
imp::set_handler(signal, handler.into()).into()
|
||||
}
|
||||
|
||||
pub fn init(main: bool) {
|
||||
if main {
|
||||
imp::setup_signal_full(SIGNAL_STACK_SIZE)
|
||||
.expect("Couldn't setup signal handler for the main thread");
|
||||
} else {
|
||||
imp::setup_signal_stack(SIGNAL_STACK_SIZE).expect("Couldn't setup thread signal stack");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
use yggdrasil_rt::time::{self as rt, SystemTime as SysTimespec};
|
||||
|
||||
use crate::time::Duration;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
pub struct Instant(pub(crate) SysTimespec);
|
||||
|
||||
impl Instant {
|
||||
pub fn now() -> Self {
|
||||
Self(rt::get_monotonic_time().expect("Could not retrieve monotonic time value"))
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
self.0.checked_add_duration(other).map(Self)
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
self.0.checked_sub_duration(other).map(Self)
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.0.checked_sub_time(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
pub struct SystemTime(pub(crate) SysTimespec);
|
||||
|
||||
pub const UNIX_EPOCH: SystemTime = SystemTime(SysTimespec::ZERO);
|
||||
|
||||
impl SystemTime {
|
||||
pub const MAX: SystemTime = SystemTime(SysTimespec::MAX);
|
||||
|
||||
pub const MIN: SystemTime = SystemTime(SysTimespec::MIN);
|
||||
|
||||
pub fn now() -> Self {
|
||||
Self(rt::get_real_time().expect("Could not retrieve real time value"))
|
||||
}
|
||||
|
||||
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
||||
self.0.sub_time(&other.0)
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Self> {
|
||||
self.0.checked_add_duration(other).map(Self)
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Self> {
|
||||
self.0.checked_sub_duration(other).map(Self)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
use crate::env;
|
||||
use crate::path::PathBuf;
|
||||
|
||||
pub fn resolve_binary(name: &str) -> Option<String> {
|
||||
// Already an absolute path
|
||||
if name.starts_with('/') {
|
||||
return None;
|
||||
}
|
||||
|
||||
let Ok(path) = env::var("PATH") else {
|
||||
return None;
|
||||
};
|
||||
|
||||
for entry in path.split(':') {
|
||||
let full_path = PathBuf::from(entry).join(name);
|
||||
|
||||
if full_path.exists() {
|
||||
return Some(full_path.to_str().unwrap().to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
macro_rules! impl_random_safe {
|
||||
($($ty:ty),+) => {
|
||||
$(impl RandomSafe for $ty {
|
||||
unsafe fn __randomize(&mut self) {
|
||||
let bytes: &mut [u8; size_of::<Self>()] = unsafe { $crate::mem::transmute(self) };
|
||||
crate::sys::random::fill_bytes(bytes);
|
||||
}
|
||||
})+
|
||||
};
|
||||
}
|
||||
|
||||
pub trait RandomSafe: Default {
|
||||
unsafe fn __randomize(&mut self);
|
||||
}
|
||||
|
||||
impl_random_safe!(u8, u16, u32, u64);
|
||||
|
||||
pub fn random<T: RandomSafe>() -> T {
|
||||
let mut v = T::default();
|
||||
unsafe {
|
||||
v.__randomize();
|
||||
}
|
||||
v
|
||||
}
|
||||
@@ -13,6 +13,10 @@ cfg_select! {
|
||||
mod motor;
|
||||
pub use motor::{Pipe, pipe};
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::{Pipe, pipe};
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use unsupported::{Pipe, pipe};
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
#![allow(exported_private_dependencies)]
|
||||
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, PipeReader, PipeWriter};
|
||||
use crate::os::fd::{AsRawFd, IntoRawFd, OwnedFd, RawFd};
|
||||
use crate::os::yggdrasil::io::pipe as os_pipe;
|
||||
use crate::sys::fd::FileDesc;
|
||||
use crate::sys::{FromInner, IntoInner};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Pipe(FileDesc);
|
||||
|
||||
impl Pipe {
|
||||
pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.read(buffer)
|
||||
}
|
||||
|
||||
pub fn read_buf(&self, buffer: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
self.0.read_buf(buffer)
|
||||
}
|
||||
|
||||
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.0.read_vectored(bufs)
|
||||
}
|
||||
|
||||
pub fn is_read_vectored(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buffer: &mut Vec<u8>) -> io::Result<usize> {
|
||||
self.0.read_to_end(buffer)
|
||||
}
|
||||
|
||||
pub fn write(&self, buffer: &[u8]) -> io::Result<usize> {
|
||||
self.0.write(buffer)
|
||||
}
|
||||
|
||||
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
self.0.write_vectored(bufs)
|
||||
}
|
||||
|
||||
pub fn is_write_vectored(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn try_clone(&self) -> io::Result<Self> {
|
||||
self.0.try_clone().map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Pipe {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Pipe {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.0.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<FileDesc> for Pipe {
|
||||
fn from_inner(fd: FileDesc) -> Self {
|
||||
Self(fd)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<OwnedFd> for Pipe {
|
||||
fn from_inner(fd: OwnedFd) -> Self {
|
||||
Self(FileDesc::from_inner(fd))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<FileDesc> for Pipe {
|
||||
fn into_inner(self) -> FileDesc {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pipe() -> io::Result<(Pipe, Pipe)> {
|
||||
let (p0, p1) = os_pipe::create_pipe_pair(false, false)?;
|
||||
Ok((Pipe::from_inner(p0), Pipe::from_inner(p1)))
|
||||
}
|
||||
|
||||
// pub fn read2(p1: Pipe, v1: &mut Vec<u8>, p2: Pipe, v2: &mut Vec<u8>) -> io::Result<()> {
|
||||
// let p1 = p1.into_inner();
|
||||
// let p2 = p2.into_inner();
|
||||
//
|
||||
// let mut poll = PollChannel::new()?;
|
||||
// poll.add(p1.as_raw_fd())?;
|
||||
// poll.add(p2.as_raw_fd())?;
|
||||
//
|
||||
// loop {
|
||||
// match poll.wait(None, true)? {
|
||||
// Some((fd, _)) if fd == p1.as_raw_fd() => {
|
||||
// p1.read_to_end(v1)?;
|
||||
// p2.read_to_end(v2)?;
|
||||
// break;
|
||||
// }
|
||||
// Some((fd, _)) if fd == p2.as_raw_fd() => {
|
||||
// p2.read_to_end(v2)?;
|
||||
// p1.read_to_end(v1)?;
|
||||
// }
|
||||
// _ => continue,
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl IntoRawFd for PipeReader {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.0.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl IntoRawFd for PipeWriter {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.0.into_raw_fd()
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,10 @@ cfg_select! {
|
||||
mod motor;
|
||||
use motor as imp;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
use yggdrasil as imp;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
use unsupported as imp;
|
||||
@@ -43,7 +47,8 @@ pub use imp::{
|
||||
))
|
||||
),
|
||||
target_os = "windows",
|
||||
target_os = "motor"
|
||||
target_os = "motor",
|
||||
target_os = "yggdrasil"
|
||||
))]
|
||||
pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
|
||||
let (mut process, mut pipes) = cmd.spawn(Stdio::MakePipe, false)?;
|
||||
@@ -81,6 +86,7 @@ pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec<u8>, Vec<
|
||||
))
|
||||
),
|
||||
target_os = "windows",
|
||||
target_os = "motor"
|
||||
target_os = "motor",
|
||||
target_os = "yggdrasil"
|
||||
)))]
|
||||
pub use imp::output;
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
use yggdrasil_rt::process::{
|
||||
ProcessGroupId as OsProcessGroupId, SpawnFlags, SpawnOption, SpawnOptions,
|
||||
};
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use super::{ChildPipes, Process, Stdio};
|
||||
use crate::ffi::OsStr;
|
||||
use crate::os::fd::RawFd;
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::process::StdioPipes;
|
||||
use crate::sys::process::env::{CommandEnv, CommandEnvs};
|
||||
use crate::sys::util;
|
||||
use crate::{fmt, io};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Command {
|
||||
program: String,
|
||||
args: Vec<String>,
|
||||
env: CommandEnv,
|
||||
cwd: Option<PathBuf>,
|
||||
pub(crate) root: Option<PathBuf>,
|
||||
|
||||
pub(crate) pgroup: Option<OsProcessGroupId>,
|
||||
pub(crate) gain_terminal: Option<RawFd>,
|
||||
pub(crate) attach_trace: bool,
|
||||
pub(crate) flags: SpawnFlags,
|
||||
|
||||
stdin: Stdio,
|
||||
stdout: Stdio,
|
||||
stderr: Stdio,
|
||||
}
|
||||
|
||||
pub struct CommandArgs<'a>(crate::slice::Iter<'a, String>);
|
||||
|
||||
impl Command {
|
||||
pub fn new(program: &OsStr) -> Self {
|
||||
let program = program.to_str().unwrap().to_owned();
|
||||
|
||||
Self {
|
||||
program,
|
||||
args: vec![],
|
||||
env: Default::default(),
|
||||
cwd: None,
|
||||
root: None,
|
||||
pgroup: None,
|
||||
gain_terminal: None,
|
||||
attach_trace: false,
|
||||
flags: SpawnFlags::const_default(),
|
||||
stdin: Stdio::Inherit,
|
||||
stdout: Stdio::Inherit,
|
||||
stderr: Stdio::Inherit,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arg(&mut self, arg: &OsStr) {
|
||||
if arg.len() == 0 {
|
||||
self.args.push(String::new());
|
||||
} else {
|
||||
let arg = arg.to_str().unwrap().to_owned();
|
||||
self.args.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn env_mut(&mut self) -> &mut CommandEnv {
|
||||
&mut self.env
|
||||
}
|
||||
|
||||
pub fn cwd(&mut self, dir: &OsStr) {
|
||||
self.cwd = Some(dir.into());
|
||||
}
|
||||
|
||||
pub fn stdin(&mut self, stdin: Stdio) {
|
||||
self.stdin = stdin;
|
||||
}
|
||||
|
||||
pub fn stdout(&mut self, stdout: Stdio) {
|
||||
self.stdout = stdout;
|
||||
}
|
||||
|
||||
pub fn stderr(&mut self, stderr: Stdio) {
|
||||
self.stderr = stderr;
|
||||
}
|
||||
|
||||
pub fn get_program(&self) -> &OsStr {
|
||||
self.program.as_str().as_ref()
|
||||
}
|
||||
|
||||
pub fn get_args(&self) -> CommandArgs<'_> {
|
||||
CommandArgs(self.args.iter())
|
||||
}
|
||||
|
||||
pub fn get_envs(&self) -> CommandEnvs<'_> {
|
||||
self.env.iter()
|
||||
}
|
||||
|
||||
pub fn get_env_clear(&self) -> bool {
|
||||
self.env.does_clear()
|
||||
}
|
||||
|
||||
pub fn get_current_dir(&self) -> Option<&Path> {
|
||||
self.cwd.as_deref()
|
||||
}
|
||||
|
||||
pub fn spawn(
|
||||
&mut self,
|
||||
_default: Stdio,
|
||||
_needs_stdin: bool,
|
||||
) -> io::Result<(Process, StdioPipes)> {
|
||||
// let default_stdin = if needs_stdin { &default } else { &self.stdin };
|
||||
|
||||
let stdin = &self.stdin;
|
||||
let stdout = &self.stdout;
|
||||
let stderr = &self.stderr;
|
||||
|
||||
let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
|
||||
let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
|
||||
let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
|
||||
|
||||
let ours = StdioPipes { stdin: our_stdin, stdout: our_stdout, stderr: our_stderr };
|
||||
let theirs = ChildPipes { stdin: their_stdin, stdout: their_stdout, stderr: their_stderr };
|
||||
|
||||
let process = self.do_spawn(&theirs)?;
|
||||
|
||||
Ok((process, ours))
|
||||
}
|
||||
|
||||
fn do_spawn(&mut self, pipes: &ChildPipes) -> io::Result<Process> {
|
||||
let mut optional = Vec::new();
|
||||
|
||||
if let Some(stdin) = pipes.stdin.as_inherit_option(RawFd::STDIN) {
|
||||
optional.push(stdin);
|
||||
}
|
||||
if let Some(stdout) = pipes.stdout.as_inherit_option(RawFd::STDOUT) {
|
||||
optional.push(stdout);
|
||||
}
|
||||
if let Some(stderr) = pipes.stderr.as_inherit_option(RawFd::STDERR) {
|
||||
optional.push(stderr);
|
||||
}
|
||||
|
||||
if let Some(pgroup) = self.pgroup {
|
||||
optional.push(SpawnOption::SetProcessGroup(pgroup));
|
||||
}
|
||||
|
||||
if let Some(fd) = self.gain_terminal {
|
||||
optional.push(SpawnOption::GainTerminal(fd));
|
||||
}
|
||||
|
||||
if self.attach_trace {
|
||||
optional.push(SpawnOption::AttachTrace);
|
||||
}
|
||||
|
||||
let program = self.program.as_str();
|
||||
let arguments = &Vec::from_iter(
|
||||
crate::iter::once(self.program.as_str())
|
||||
.chain(self.args.iter().map(|arg| arg.as_str())),
|
||||
);
|
||||
|
||||
let program = &util::resolve_binary(program).unwrap_or_else(|| program.to_owned());
|
||||
|
||||
let envs = Vec::from_iter(self.env.capture().iter().filter_map(|(key, value)| {
|
||||
let key = key.to_str()?;
|
||||
let value = value.to_str()?;
|
||||
Some(format!("{}={}", key, value))
|
||||
}));
|
||||
|
||||
let directory = self.cwd.as_ref().map(|cwd| cwd.to_str().unwrap());
|
||||
let root = self.root.as_ref().map(|root| root.to_str().unwrap());
|
||||
|
||||
let environment = &Vec::from_iter(envs.iter().map(|x| x.as_str()));
|
||||
|
||||
let options = SpawnOptions {
|
||||
program,
|
||||
arguments,
|
||||
environment,
|
||||
directory,
|
||||
root,
|
||||
optional: &optional,
|
||||
flags: self.flags,
|
||||
};
|
||||
|
||||
let pid = unsafe { syscall::spawn_process(&options) }?;
|
||||
|
||||
Ok(Process { pid })
|
||||
}
|
||||
|
||||
pub(crate) fn change_root<P: AsRef<Path>>(&mut self, root: P) {
|
||||
self.root = Some(root.as_ref().into());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for CommandArgs<'a> {
|
||||
type Item = &'a OsStr;
|
||||
fn next(&mut self) -> Option<&'a OsStr> {
|
||||
self.0.next().map(|s| s.as_ref())
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.0.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for CommandArgs<'a> {}
|
||||
|
||||
impl<'a> fmt::Debug for CommandArgs<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
#![allow(exported_private_dependencies)]
|
||||
|
||||
use yggdrasil_rt::process::{
|
||||
self as rt, ExitCode as OsExitCode, ProcessId as OsProcessId, ProcessWait, Signal as OsSignal,
|
||||
WaitFlags,
|
||||
};
|
||||
use yggdrasil_rt::sys as syscall;
|
||||
|
||||
use crate::io;
|
||||
use crate::os::fd::AsRawFd;
|
||||
use crate::os::yggdrasil::io::poll::PollChannel;
|
||||
|
||||
mod command;
|
||||
mod status;
|
||||
mod stdio;
|
||||
|
||||
pub use command::{Command, CommandArgs};
|
||||
pub use status::{ExitCode, ExitStatus, ExitStatusError};
|
||||
pub use stdio::{ChildPipes, Stdio};
|
||||
|
||||
pub use crate::ffi::OsString as EnvKey;
|
||||
|
||||
// Process
|
||||
|
||||
pub struct Process {
|
||||
pid: OsProcessId,
|
||||
}
|
||||
|
||||
impl Process {
|
||||
pub fn id(&self) -> u32 {
|
||||
self.pid.into_raw()
|
||||
}
|
||||
|
||||
pub fn main_thread_id(&self) -> io::Result<u32> {
|
||||
Ok(rt::get_process_option!(Some(self.pid), rt::options::MainThread)?.into_raw())
|
||||
}
|
||||
|
||||
pub fn kill(&mut self) -> io::Result<()> {
|
||||
unsafe { syscall::send_signal(self.pid, OsSignal::Killed) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn wait_impl(&mut self, flags: WaitFlags) -> io::Result<ExitStatus> {
|
||||
let mut status = OsExitCode::Exited(0);
|
||||
unsafe { syscall::wait_process(&ProcessWait::Process(self.pid), &mut status, flags) }?;
|
||||
Ok(ExitStatus(status))
|
||||
}
|
||||
|
||||
pub fn wait(&mut self) -> io::Result<ExitStatus> {
|
||||
self.wait_impl(WaitFlags::empty())
|
||||
}
|
||||
|
||||
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
|
||||
match self.wait_impl(WaitFlags::NON_BLOCKING) {
|
||||
Ok(s) => Ok(Some(s)),
|
||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ChildPipe
|
||||
|
||||
pub type ChildPipe = crate::sys::pipe::Pipe;
|
||||
|
||||
pub fn read_output(
|
||||
out: ChildPipe,
|
||||
stdout: &mut Vec<u8>,
|
||||
err: ChildPipe,
|
||||
stderr: &mut Vec<u8>,
|
||||
) -> io::Result<()> {
|
||||
let mut poll = PollChannel::new()?;
|
||||
poll.add(out.as_raw_fd())?;
|
||||
poll.add(err.as_raw_fd())?;
|
||||
|
||||
loop {
|
||||
match poll.wait(None, true)? {
|
||||
Some((fd, _)) if fd == out.as_raw_fd() => {
|
||||
out.read_to_end(stdout)?;
|
||||
err.read_to_end(stderr)?;
|
||||
break;
|
||||
}
|
||||
Some((fd, _)) if fd == err.as_raw_fd() => {
|
||||
err.read_to_end(stderr)?;
|
||||
out.read_to_end(stdout)?;
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
use yggdrasil_rt::process::{ExitCode as OsExitCode, Signal as OsSignal};
|
||||
|
||||
use crate::fmt;
|
||||
use crate::num::NonZeroI32;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ExitStatus(pub(super) OsExitCode);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct ExitStatusError(pub(super) NonZeroI32);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct ExitCode(pub(super) bool);
|
||||
|
||||
impl ExitStatus {
|
||||
pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
|
||||
if let Some(error) = self.0.as_failure() { Err(ExitStatusError(error)) } else { Ok(()) }
|
||||
}
|
||||
|
||||
pub fn code(&self) -> Option<i32> {
|
||||
match self.0 {
|
||||
OsExitCode::Exited(code) => Some(code),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signal(&self) -> Option<Result<OsSignal, u32>> {
|
||||
self.0.signal()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ExitStatus {
|
||||
fn default() -> Self {
|
||||
Self(OsExitCode::SUCCESS)
|
||||
}
|
||||
}
|
||||
|
||||
impl ExitStatusError {
|
||||
pub fn code(self) -> Option<NonZeroI32> {
|
||||
Some(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExitStatusError> for ExitStatus {
|
||||
fn from(value: ExitStatusError) -> Self {
|
||||
Self(OsExitCode::from(i32::from(value.0)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ExitCode {
|
||||
pub const SUCCESS: Self = Self(false);
|
||||
pub const FAILURE: Self = Self(true);
|
||||
|
||||
pub fn as_i32(&self) -> i32 {
|
||||
self.0 as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for ExitCode {
|
||||
fn from(value: u8) -> Self {
|
||||
Self(value != 0)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ExitStatus {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ExitStatus {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
use yggdrasil_rt::process::SpawnOption;
|
||||
|
||||
use crate::io::{self, Stderr, Stdin, Stdout};
|
||||
use crate::os::fd::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||
use crate::os::yggdrasil::io::pipe as os_pipe;
|
||||
use crate::sys::FromInner;
|
||||
use crate::sys::fs::File;
|
||||
use crate::sys::pipe::Pipe;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ChildPipes {
|
||||
pub stdin: ChildStdio,
|
||||
pub stdout: ChildStdio,
|
||||
pub stderr: ChildStdio,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ChildStdio {
|
||||
Inherit,
|
||||
Null,
|
||||
CopyFd(RawFd),
|
||||
MoveFd(RawFd),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Stdio {
|
||||
Inherit,
|
||||
Null,
|
||||
MakePipe,
|
||||
MoveFd(RawFd),
|
||||
CopyFd(RawFd),
|
||||
}
|
||||
|
||||
impl Stdio {
|
||||
pub fn to_child_stdio(&self, readable: bool) -> io::Result<(ChildStdio, Option<Pipe>)> {
|
||||
match self {
|
||||
Stdio::Inherit => Ok((ChildStdio::Inherit, None)),
|
||||
Stdio::Null => Ok((ChildStdio::Null, None)),
|
||||
Stdio::MakePipe => {
|
||||
let (read, write) = os_pipe::create_pipe_pair(false, false)?;
|
||||
|
||||
if readable {
|
||||
let write = Pipe::from_inner(write);
|
||||
Ok((ChildStdio::MoveFd(read.into_raw_fd()), Some(write)))
|
||||
} else {
|
||||
let read = Pipe::from_inner(read);
|
||||
Ok((ChildStdio::MoveFd(write.into_raw_fd()), Some(read)))
|
||||
}
|
||||
}
|
||||
Stdio::MoveFd(fd) => Ok((ChildStdio::MoveFd(*fd), None)),
|
||||
Stdio::CopyFd(fd) => Ok((ChildStdio::CopyFd(*fd), None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(ineffective_unstable_trait_impl)]
|
||||
#[unstable(feature = "yggdrasil_os", issue = "none")]
|
||||
impl FromRawFd for crate::process::Stdio {
|
||||
#[inline]
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> crate::process::Stdio {
|
||||
let io = Stdio::MoveFd(fd);
|
||||
crate::process::Stdio::from_inner(io)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Pipe> for Stdio {
|
||||
fn from(pipe: Pipe) -> Stdio {
|
||||
Self::MoveFd(pipe.into_raw_fd())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<File> for Stdio {
|
||||
fn from(file: File) -> Stdio {
|
||||
Self::MoveFd(file.into_raw_fd())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Stdin> for Stdio {
|
||||
fn from(s: Stdin) -> Stdio {
|
||||
Self::CopyFd(s.as_raw_fd())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Stdout> for Stdio {
|
||||
fn from(s: Stdout) -> Stdio {
|
||||
Self::CopyFd(s.as_raw_fd())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Stderr> for Stdio {
|
||||
fn from(s: Stderr) -> Stdio {
|
||||
Self::CopyFd(s.as_raw_fd())
|
||||
}
|
||||
}
|
||||
|
||||
impl ChildStdio {
|
||||
pub(super) fn as_inherit_option(&self, child: RawFd) -> Option<SpawnOption> {
|
||||
match self {
|
||||
Self::Inherit => Some(SpawnOption::CopyFile { source: child, child }),
|
||||
&Self::MoveFd(fd) => Some(SpawnOption::MoveFile { source: fd, child }),
|
||||
&Self::CopyFd(fd) => Some(SpawnOption::CopyFile { source: fd, child }),
|
||||
Self::Null => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,6 +102,10 @@ cfg_select! {
|
||||
mod zkvm;
|
||||
pub use zkvm::fill_bytes;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::fill_bytes;
|
||||
}
|
||||
any(
|
||||
all(target_family = "wasm", target_os = "unknown"),
|
||||
target_os = "xous",
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#[inline(always)]
|
||||
pub fn fill_bytes(buffer: &mut [u8]) {
|
||||
unsafe { yggdrasil_rt::sys::get_random(buffer) }
|
||||
}
|
||||
|
||||
// pub fn hashmap_random_keys() -> (u64, u64) {
|
||||
// const KEY_LEN: usize = crate::mem::size_of::<u64>();
|
||||
//
|
||||
// let mut v = [0u8; KEY_LEN * 2];
|
||||
// fill_bytes(&mut v);
|
||||
//
|
||||
// let key1 = v[0..KEY_LEN].try_into().unwrap();
|
||||
// let key2 = v[KEY_LEN..].try_into().unwrap();
|
||||
//
|
||||
// (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2))
|
||||
// }
|
||||
@@ -45,6 +45,10 @@ cfg_select! {
|
||||
mod zkvm;
|
||||
pub use zkvm::*;
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::*;
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use unsupported::*;
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
use yggdrasil_rt::Error as OsError;
|
||||
use yggdrasil_rt::io::RawFd;
|
||||
|
||||
use crate::io;
|
||||
use crate::io::{IoSlice, IoSliceMut};
|
||||
use crate::sealed::Sealed;
|
||||
|
||||
pub struct Stdin;
|
||||
pub struct Stdout;
|
||||
pub struct Stderr;
|
||||
|
||||
impl Sealed for Stdin {}
|
||||
|
||||
impl Stdin {
|
||||
pub const fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl Sealed for Stdout {}
|
||||
|
||||
impl Stdout {
|
||||
pub const fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl Sealed for Stderr {}
|
||||
|
||||
impl Stderr {
|
||||
pub const fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Read for Stdin {
|
||||
fn read(&mut self, data: &mut [u8]) -> io::Result<usize> {
|
||||
Ok(unsafe { yggdrasil_rt::sys::read(RawFd::STDIN, data) }?)
|
||||
}
|
||||
|
||||
fn read_vectored(&mut self, _data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_read_vectored(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Write for Stdout {
|
||||
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
|
||||
Ok(unsafe { yggdrasil_rt::sys::write(RawFd::STDOUT, data) }?)
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, _data: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_write_vectored(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Write for Stderr {
|
||||
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
|
||||
Ok(unsafe { yggdrasil_rt::sys::write(RawFd::STDERR, data) }?)
|
||||
}
|
||||
|
||||
fn write_vectored(&mut self, _data: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_write_vectored(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub const STDIN_BUF_SIZE: usize = 64;
|
||||
|
||||
impl crate::io::IsTerminal for Stdin {
|
||||
fn is_terminal(&self) -> bool {
|
||||
yggdrasil_rt::io::terminal::is_terminal(RawFd::STDIN)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_ebadf(err: &io::Error) -> bool {
|
||||
err.raw_os_error() == Some(u32::from(OsError::InvalidFile) as i32)
|
||||
}
|
||||
|
||||
pub struct PanicOutput {
|
||||
stderr: Stderr,
|
||||
}
|
||||
|
||||
impl PanicOutput {
|
||||
pub fn new() -> Self {
|
||||
Self { stderr: Stderr::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl io::Write for PanicOutput {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
yggdrasil_rt::debug::trace_raw(yggdrasil_rt::debug::TraceLevel::Error, buf);
|
||||
self.stderr.write(buf).ok();
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn panic_output() -> Option<impl io::Write> {
|
||||
Some(PanicOutput::new())
|
||||
}
|
||||
@@ -10,6 +10,7 @@ cfg_select! {
|
||||
target_os = "fuchsia",
|
||||
all(target_family = "wasm", target_feature = "atomics"),
|
||||
target_os = "hermit",
|
||||
target_os = "yggdrasil",
|
||||
) => {
|
||||
mod futex;
|
||||
pub use futex::Condvar;
|
||||
|
||||
@@ -9,6 +9,7 @@ cfg_select! {
|
||||
target_os = "dragonfly",
|
||||
all(target_family = "wasm", target_feature = "atomics"),
|
||||
target_os = "hermit",
|
||||
target_os = "yggdrasil",
|
||||
) => {
|
||||
mod futex;
|
||||
pub use futex::Mutex;
|
||||
|
||||
@@ -9,7 +9,8 @@ cfg_select! {
|
||||
target_os = "fuchsia",
|
||||
all(target_family = "wasm", target_feature = "atomics"),
|
||||
target_os = "hermit",
|
||||
target_os = "motor",
|
||||
target_os = "motor",
|
||||
target_os = "yggdrasil",
|
||||
) => {
|
||||
mod futex;
|
||||
pub use futex::RwLock;
|
||||
|
||||
@@ -48,6 +48,11 @@ cfg_select! {
|
||||
mod unsupported;
|
||||
pub use unsupported::{Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod yggdrasil;
|
||||
pub use yggdrasil::{available_parallelism, sleep, Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
pub(crate) use yggdrasil::init;
|
||||
}
|
||||
any(target_family = "unix", target_os = "wasi") => {
|
||||
mod unix;
|
||||
pub use unix::{Thread, available_parallelism, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
use yggdrasil_rt::process::{self, AuxValue, ExitCode as OsExitCode, thread as rt, thread_local};
|
||||
|
||||
use crate::boxed::Box;
|
||||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::thread::ThreadInit;
|
||||
use crate::time::Duration;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Thread {
|
||||
inner: rt::ThreadHandle<()>,
|
||||
}
|
||||
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 8192;
|
||||
|
||||
// TODO put it into OnceLock
|
||||
pub(super) static mut TLS_IMAGE: Option<thread_local::TlsImage> = None;
|
||||
|
||||
impl Thread {
|
||||
pub unsafe fn new(stack_size: usize, init: Box<ThreadInit>) -> io::Result<Thread> {
|
||||
// Unused now
|
||||
let _ = set_name;
|
||||
let info = rt::ThreadCreateInfo {
|
||||
signal_stack: rt::ThreadSignalStack::Allocate(4096 * 8),
|
||||
stack: rt::ThreadStack::Allocate(stack_size),
|
||||
entry: rt::ThreadFunction::Pointer(Self::entry),
|
||||
#[allow(static_mut_refs)]
|
||||
tls_image: TLS_IMAGE.as_ref(),
|
||||
};
|
||||
let inner = rt::Thread::spawn(info, init, false)?;
|
||||
Ok(Thread { inner })
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
self.inner.join_uninterruptible();
|
||||
}
|
||||
|
||||
fn entry(init: Box<ThreadInit>) {
|
||||
let start = init.init();
|
||||
(start)();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_name(name: &CStr) {
|
||||
rt::Thread::<()>::set_name(
|
||||
name.to_str().expect("Thread::set_name() expects a valid UTF-8 string"),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn current_os_id() -> Option<u64> {
|
||||
Some(unsafe { yggdrasil_rt::sys::get_tid() as u64 })
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
yggdrasil_rt::debug_trace!(Error, "thread::yield_now()");
|
||||
loop {}
|
||||
}
|
||||
|
||||
pub fn sleep(duration: Duration) {
|
||||
process::uninterruptible_sleep(duration)
|
||||
}
|
||||
|
||||
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
|
||||
yggdrasil_rt::debug_trace!(Error, "thread::available_parallelism()");
|
||||
loop {}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn init<'a, I: Iterator<Item = &'a AuxValue>>(auxv: I) {
|
||||
// Rust doesn't have a pthread_self, so just reserve two slots in the TCB:
|
||||
// * self-pointer
|
||||
// * DTV pointer
|
||||
let image = thread_local::TlsImage::from_auxv(auxv);
|
||||
if let Err(error) = thread_local::init_tls(image.as_ref(), false) {
|
||||
yggdrasil_rt::debug_trace!(Debug, "Could not setup main thread TLS: {error:?}");
|
||||
// TODO kill self with ABORTED signal instead
|
||||
yggdrasil_rt::sys::exit_process(OsExitCode::Exited(1));
|
||||
}
|
||||
TLS_IMAGE = image;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
use yggdrasil_rt::process::thread_local as imp;
|
||||
|
||||
pub type Key = usize;
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn set(key: Key, value: *mut u8) {
|
||||
let dtv = imp::get_dtv();
|
||||
dtv.set_specific(key, value.cast(), true);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
|
||||
// TODO dtors
|
||||
let dtv = imp::get_dtv();
|
||||
dtv.new_specific()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn destroy(_key: Key) {
|
||||
// TODO dtors
|
||||
}
|
||||
@@ -195,6 +195,15 @@ pub(crate) mod key {
|
||||
pub(super) use moto_rt::tls::{Key, get, set};
|
||||
use moto_rt::tls::{create, destroy};
|
||||
}
|
||||
target_os = "yggdrasil" => {
|
||||
mod racy;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod yggdrasil;
|
||||
pub(super) use racy::LazyKey;
|
||||
pub(super) use yggdrasil::{Key, set};
|
||||
use yggdrasil::{create, destroy};
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -930,29 +930,41 @@ impl Step for StartupObjects {
|
||||
let target = self.target;
|
||||
// Even though no longer necessary on x86_64, they are kept for now to
|
||||
// avoid potential issues in downstream crates.
|
||||
if !target.is_windows_gnu() {
|
||||
if !target.is_windows_gnu() && !target.ends_with("-yggdrasil") {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
let mut target_deps = vec![];
|
||||
if target.ends_with("-yggdrasil") {
|
||||
let dst_dir = &builder.native_dir(target).join("rtstartup");
|
||||
let sysroot_dir = &builder.sysroot_target_libdir(for_compiler, target);
|
||||
t!(fs::create_dir_all(dst_dir));
|
||||
|
||||
let src_dir = &builder.src.join("library").join("rtstartup");
|
||||
let dst_dir = &builder.native_dir(target).join("rtstartup");
|
||||
let sysroot_dir = &builder.sysroot_target_libdir(for_compiler, target);
|
||||
t!(fs::create_dir_all(dst_dir));
|
||||
let src_file = &builder.src.join("library/rtstartup/yggdrasil_rust_entry.rs");
|
||||
let dst_file = &dst_dir.join("rust_entry0.o");
|
||||
let target_file = sysroot_dir.join("rust_entry0.o");
|
||||
|
||||
for file in &["rsbegin", "rsend"] {
|
||||
let src_file = &src_dir.join(file.to_string() + ".rs");
|
||||
let dst_file = &dst_dir.join(file.to_string() + ".o");
|
||||
if !up_to_date(src_file, dst_file) {
|
||||
let mut cmd = command(&builder.initial_rustc);
|
||||
// FIXME(alnyan) do this properly
|
||||
|
||||
let fake_target = if target.starts_with("aarch64-") {
|
||||
"aarch64-unknown-none"
|
||||
} else if target.starts_with("x86_64-") {
|
||||
"x86_64-unknown-none"
|
||||
} else if target.starts_with("i686-") {
|
||||
"i686-unknown-linux-gnu"
|
||||
} else if target.starts_with("riscv64-") {
|
||||
"riscv64imac-unknown-none-elf"
|
||||
} else {
|
||||
unimplemented!("This code shouldn't be reachable");
|
||||
};
|
||||
|
||||
cmd.env("RUSTC_BOOTSTRAP", "1");
|
||||
if !builder.local_rebuild {
|
||||
// a local_rebuild compiler already has stage1 features
|
||||
cmd.arg("--cfg").arg("bootstrap");
|
||||
}
|
||||
cmd.arg("--target")
|
||||
.arg(target.rustc_target_arg())
|
||||
.arg(fake_target)
|
||||
.arg("--emit=obj")
|
||||
.arg("-o")
|
||||
.arg(dst_file)
|
||||
@@ -960,12 +972,45 @@ impl Step for StartupObjects {
|
||||
.run(builder);
|
||||
}
|
||||
|
||||
let obj = sysroot_dir.join((*file).to_string() + ".o");
|
||||
builder.copy_link(dst_file, &obj, FileType::NativeLibrary);
|
||||
target_deps.push((obj, DependencyType::Target));
|
||||
}
|
||||
builder.copy_link(dst_file, &target_file, FileType::NativeLibrary);
|
||||
// builder.copy_link(dst_file, &target);
|
||||
// target_deps.push((target, DependencyType::Target));
|
||||
|
||||
target_deps
|
||||
vec![(target_file, DependencyType::Target)]
|
||||
} else {
|
||||
let mut target_deps = vec![];
|
||||
|
||||
let src_dir = &builder.src.join("library").join("rtstartup");
|
||||
let dst_dir = &builder.native_dir(target).join("rtstartup");
|
||||
let sysroot_dir = &builder.sysroot_target_libdir(for_compiler, target);
|
||||
t!(fs::create_dir_all(dst_dir));
|
||||
|
||||
for file in &["rsbegin", "rsend"] {
|
||||
let src_file = &src_dir.join(file.to_string() + ".rs");
|
||||
let dst_file = &dst_dir.join(file.to_string() + ".o");
|
||||
if !up_to_date(src_file, dst_file) {
|
||||
let mut cmd = command(&builder.initial_rustc);
|
||||
cmd.env("RUSTC_BOOTSTRAP", "1");
|
||||
if !builder.local_rebuild {
|
||||
// a local_rebuild compiler already has stage1 features
|
||||
cmd.arg("--cfg").arg("bootstrap");
|
||||
}
|
||||
cmd.arg("--target")
|
||||
.arg(target.rustc_target_arg())
|
||||
.arg("--emit=obj")
|
||||
.arg("-o")
|
||||
.arg(dst_file)
|
||||
.arg(src_file)
|
||||
.run(builder);
|
||||
}
|
||||
|
||||
let obj = sysroot_dir.join((*file).to_string() + ".o");
|
||||
builder.copy_link(dst_file, &obj, FileType::NativeLibrary);
|
||||
target_deps.push((obj, DependencyType::Target));
|
||||
}
|
||||
|
||||
target_deps
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,9 @@ pub struct Finder {
|
||||
const STAGE0_MISSING_TARGETS: &[&str] = &[
|
||||
// just a dummy comment so the list doesn't get onelined
|
||||
"riscv64im-unknown-none-elf",
|
||||
"x86_64-unknown-yggdrasil",
|
||||
"aarch64-unknown-yggdrasil",
|
||||
"riscv64-unknown-yggdrasil",
|
||||
];
|
||||
|
||||
/// Minimum version threshold for libstdc++ required when using prebuilt LLVM
|
||||
|
||||
@@ -444,6 +444,7 @@ impl fmt::Display for Display<'_> {
|
||||
"watchos" => "watchOS",
|
||||
"windows" => "Windows",
|
||||
"visionos" => "visionOS",
|
||||
"yggdrasil" => "Yggdrasil",
|
||||
_ => "",
|
||||
},
|
||||
(sym::target_arch, Some(arch)) => match arch.as_str() {
|
||||
|
||||
Reference in New Issue
Block a user