Auto merge of #60547 - redox-os:redox-unix, r=alexcrichton

redox: convert to target_family unix

This is the second step to supporting rust-lang/rust#60139.

In order to have a smooth transition, there will need to be a change made in liblibc at the same time, switching Redox over to the unix target family. See https://github.com/rust-lang/libc/pull/1332
This commit is contained in:
bors 2019-08-07 16:56:46 +00:00
commit ad7c55e1fc
74 changed files with 590 additions and 6440 deletions

View File

@ -1,5 +0,0 @@
# `n16`
This feature is internal to the Rust compiler and is not intended for general use.
------------------------

View File

@ -48,8 +48,7 @@ pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 {
libc::abort();
}
#[cfg(any(target_os = "redox",
windows,
#[cfg(any(windows,
all(target_arch = "wasm32", not(target_os = "emscripten"))))]
unsafe fn abort() -> ! {
core::intrinsics::abort();

View File

@ -0,0 +1,20 @@
use crate::spec::{LinkerFlavor, Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::redox_base::opts();
base.max_atomic_width = Some(128);
Ok(Target {
llvm_target: "aarch64-unknown-redox".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
target_c_int_width: "32".to_string(),
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
arch: "aarch64".to_string(),
target_os: "redox".to_string(),
target_env: "relibc".to_string(),
target_vendor: "unknown".to_string(),
linker_flavor: LinkerFlavor::Gcc,
options: base,
})
}

View File

@ -417,6 +417,7 @@ supported_targets! {
("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc),
("aarch64-unknown-redox", aarch64_unknown_redox),
("x86_64-unknown-redox", x86_64_unknown_redox),
("i386-apple-ios", i386_apple_ios),

View File

@ -1,4 +1,4 @@
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions, RelroLevel};
use std::default::Default;
pub fn opts() -> TargetOptions {
@ -18,14 +18,17 @@ pub fn opts() -> TargetOptions {
]);
TargetOptions {
pre_link_args: args,
dynamic_linking: true,
executables: true,
relocation_model: "static".to_string(),
disable_redzone: true,
eliminate_frame_pointer: false,
target_family: None,
target_family: Some("unix".to_string()),
linker_is_gnu: true,
has_rpath: true,
pre_link_args: args,
position_independent_executables: true,
relro_level: RelroLevel::Full,
has_elf_tls: true,
crt_static_default: true,
crt_static_respected: true,
.. Default::default()
}
}

View File

@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
arch: "x86_64".to_string(),
target_os: "redox".to_string(),
target_env: String::new(),
target_env: "relibc".to_string(),
target_vendor: "unknown".to_string(),
linker_flavor: LinkerFlavor::Gcc,
options: base,

View File

@ -50,6 +50,7 @@ cfg_if::cfg_if! {
#[cfg(target_os = "emscripten")] pub mod emscripten;
#[cfg(target_os = "fuchsia")] pub mod fuchsia;
#[cfg(target_os = "hermit")] pub mod hermit;
#[cfg(target_os = "redox")] pub mod redox;
#[cfg(target_os = "wasi")] pub mod wasi;
#[cfg(target_os = "vxworks")] pub mod vxworks;
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] pub mod fortanix_sgx;

383
src/libstd/os/redox/fs.rs Normal file
View File

@ -0,0 +1,383 @@
#![stable(feature = "metadata_ext", since = "1.1.0")]
use crate::fs::Metadata;
use crate::sys_common::AsInner;
#[allow(deprecated)]
use crate::os::redox::raw;
/// OS-specific extensions to [`fs::Metadata`].
///
/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
/// the raw information returned by the OS.
///
/// The contents of the returned [`stat`] are **not** consistent across
/// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
/// cross-Unix abstractions contained within the raw stat.
///
/// [`stat`]: ../../../../std/os/redox/raw/struct.stat.html
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let stat = meta.as_raw_stat();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
#[rustc_deprecated(since = "1.8.0",
reason = "deprecated in favor of the accessor \
methods of this trait")]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
/// Returns the device ID on which this file resides.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_dev());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_dev(&self) -> u64;
/// Returns the inode number.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_ino());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ino(&self) -> u64;
/// Returns the file type and mode.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_mode());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mode(&self) -> u32;
/// Returns the number of hard links to file.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_nlink());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_nlink(&self) -> u64;
/// Returns the user ID of the file owner.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_uid());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_uid(&self) -> u32;
/// Returns the group ID of the file owner.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_gid());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_gid(&self) -> u32;
/// Returns the device ID that this file represents. Only relevant for special file.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_rdev());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_rdev(&self) -> u64;
/// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
///
/// The size of a symbolic link is the length of the pathname it contains,
/// without a terminating null byte.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_size());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_size(&self) -> u64;
/// Returns the last access time of the file, in seconds since Unix Epoch.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_atime());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_atime(&self) -> i64;
/// Returns the last access time of the file, in nanoseconds since [`st_atime`].
///
/// [`st_atime`]: #tymethod.st_atime
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_atime_nsec());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_atime_nsec(&self) -> i64;
/// Returns the last modification time of the file, in seconds since Unix Epoch.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_mtime());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mtime(&self) -> i64;
/// Returns the last modification time of the file, in nanoseconds since [`st_mtime`].
///
/// [`st_mtime`]: #tymethod.st_mtime
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_mtime_nsec());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mtime_nsec(&self) -> i64;
/// Returns the last status change time of the file, in seconds since Unix Epoch.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_ctime());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime(&self) -> i64;
/// Returns the last status change time of the file, in nanoseconds since [`st_ctime`].
///
/// [`st_ctime`]: #tymethod.st_ctime
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_ctime_nsec());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime_nsec(&self) -> i64;
/// Returns the "preferred" blocksize for efficient filesystem I/O.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_blksize());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_blksize(&self) -> u64;
/// Returns the number of blocks allocated to the file, 512-byte units.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::redox::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_blocks());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_blocks(&self) -> u64;
}
#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for Metadata {
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat {
unsafe {
&*(self.as_inner().as_inner() as *const libc::stat
as *const raw::stat)
}
}
fn st_dev(&self) -> u64 {
self.as_inner().as_inner().st_dev as u64
}
fn st_ino(&self) -> u64 {
self.as_inner().as_inner().st_ino as u64
}
fn st_mode(&self) -> u32 {
self.as_inner().as_inner().st_mode as u32
}
fn st_nlink(&self) -> u64 {
self.as_inner().as_inner().st_nlink as u64
}
fn st_uid(&self) -> u32 {
self.as_inner().as_inner().st_uid as u32
}
fn st_gid(&self) -> u32 {
self.as_inner().as_inner().st_gid as u32
}
fn st_rdev(&self) -> u64 {
self.as_inner().as_inner().st_rdev as u64
}
fn st_size(&self) -> u64 {
self.as_inner().as_inner().st_size as u64
}
fn st_atime(&self) -> i64 {
self.as_inner().as_inner().st_atime as i64
}
fn st_atime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_atime_nsec as i64
}
fn st_mtime(&self) -> i64 {
self.as_inner().as_inner().st_mtime as i64
}
fn st_mtime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_mtime_nsec as i64
}
fn st_ctime(&self) -> i64 {
self.as_inner().as_inner().st_ctime as i64
}
fn st_ctime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_ctime_nsec as i64
}
fn st_blksize(&self) -> u64 {
self.as_inner().as_inner().st_blksize as u64
}
fn st_blocks(&self) -> u64 {
self.as_inner().as_inner().st_blocks as u64
}
}

View File

@ -0,0 +1,6 @@
//! Redox-specific definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
pub mod raw;
pub mod fs;

View File

@ -0,0 +1,67 @@
//! Redox-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
#![rustc_deprecated(since = "1.8.0",
reason = "these type aliases are no longer supported by \
the standard library, the `libc` crate on \
crates.io should be used instead for the correct \
definitions")]
#![allow(deprecated)]
#![allow(missing_debug_implementations)]
use crate::os::raw::{c_char, c_int, c_long, c_ulong, c_void};
#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = c_long;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type gid_t = c_int;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = c_int;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type uid_t = c_int;
#[stable(feature = "pthread_t", since = "1.8.0")]
pub type pthread_t = *mut c_void;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = c_ulong;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = c_ulong;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = c_ulong;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = c_ulong;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = c_long;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = c_long;
#[repr(C)]
#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_dev: dev_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ino: ino_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_nlink: nlink_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mode: mode_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_uid: uid_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_gid: gid_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_rdev: dev_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_size: off_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_blksize: blksize_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_blocks: blkcnt_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_atime: time_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_atime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mtime: time_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mtime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ctime: time_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ctime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub _pad: [c_char; 24],
}

View File

@ -317,7 +317,7 @@ unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
// Detect scheme on Redox
fn has_redox_scheme(s: &[u8]) -> bool {
cfg!(target_os = "redox") && s.split(|b| *b == b'/').next().unwrap_or(b"").contains(&b':')
cfg!(target_os = "redox") && s.contains(&b':')
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -35,9 +35,6 @@ cfg_if::cfg_if! {
} else if #[cfg(target_os = "cloudabi")] {
mod cloudabi;
pub use self::cloudabi::*;
} else if #[cfg(target_os = "redox")] {
mod redox;
pub use self::redox::*;
} else if #[cfg(target_os = "wasi")] {
mod wasi;
pub use self::wasi::*;
@ -58,7 +55,7 @@ cfg_if::cfg_if! {
#[cfg(rustdoc)]
cfg_if::cfg_if! {
if #[cfg(any(unix, target_os = "redox"))] {
if #[cfg(unix)] {
// On unix we'll document what's already available
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::ext as unix_ext;

View File

@ -1,96 +0,0 @@
//! Global initialization and retrieval of command line arguments.
//!
//! On some platforms these are stored during runtime startup,
//! and on some they are retrieved from the system on demand.
#![allow(dead_code)] // runtime init functions not used during testing
use crate::ffi::OsString;
use crate::marker::PhantomData;
use crate::vec;
/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
/// One-time global cleanup.
pub unsafe fn cleanup() { imp::cleanup() }
/// Returns the command line arguments
pub fn args() -> Args {
imp::args()
}
pub struct Args {
iter: vec::IntoIter<OsString>,
_dont_send_or_sync_me: PhantomData<*mut ()>,
}
impl Args {
pub fn inner_debug(&self) -> &[OsString] {
self.iter.as_slice()
}
}
impl Iterator for Args {
type Item = OsString;
fn next(&mut self) -> Option<OsString> { 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<OsString> { self.iter.next_back() }
}
mod imp {
use crate::os::unix::prelude::*;
use crate::mem;
use crate::ffi::{CStr, OsString};
use crate::marker::PhantomData;
use super::Args;
use crate::sys_common::mutex::Mutex;
static mut GLOBAL_ARGS_PTR: usize = 0;
static LOCK: Mutex = Mutex::new();
pub unsafe fn init(argc: isize, argv: *const *const u8) {
let args = (0..argc).map(|i| {
CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
}).collect();
let _guard = LOCK.lock();
let ptr = get_global_ptr();
assert!((*ptr).is_none());
(*ptr) = Some(box args);
}
pub unsafe fn cleanup() {
let _guard = LOCK.lock();
*get_global_ptr() = None;
}
pub fn args() -> Args {
let bytes = clone().unwrap_or_default();
let v: Vec<OsString> = bytes.into_iter().map(|v| {
OsStringExt::from_vec(v)
}).collect();
Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
}
fn clone() -> Option<Vec<Vec<u8>>> {
unsafe {
let _guard = LOCK.lock();
let ptr = get_global_ptr();
(*ptr).as_ref().map(|s| (**s).clone())
}
}
unsafe fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
mem::transmute(&GLOBAL_ARGS_PTR)
}
}

View File

@ -1,33 +0,0 @@
#![cfg(not(test))]
use libc::{c_float, c_double};
#[link_name = "m"]
extern {
pub fn acos(n: c_double) -> c_double;
pub fn acosf(n: c_float) -> c_float;
pub fn asin(n: c_double) -> c_double;
pub fn asinf(n: c_float) -> c_float;
pub fn atan(n: c_double) -> c_double;
pub fn atan2(a: c_double, b: c_double) -> c_double;
pub fn atan2f(a: c_float, b: c_float) -> c_float;
pub fn atanf(n: c_float) -> c_float;
pub fn cbrt(n: c_double) -> c_double;
pub fn cbrtf(n: c_float) -> c_float;
pub fn cosh(n: c_double) -> c_double;
pub fn coshf(n: c_float) -> c_float;
pub fn expm1(n: c_double) -> c_double;
pub fn expm1f(n: c_float) -> c_float;
pub fn fdim(a: c_double, b: c_double) -> c_double;
pub fn fdimf(a: c_float, b: c_float) -> c_float;
pub fn hypot(x: c_double, y: c_double) -> c_double;
pub fn hypotf(x: c_float, y: c_float) -> c_float;
pub fn log1p(n: c_double) -> c_double;
pub fn log1pf(n: c_float) -> c_float;
pub fn sinh(n: c_double) -> c_double;
pub fn sinhf(n: c_float) -> c_float;
pub fn tan(n: c_double) -> c_double;
pub fn tanf(n: c_float) -> c_float;
pub fn tanh(n: c_double) -> c_double;
pub fn tanhf(n: c_float) -> c_float;
}

View File

@ -1,111 +0,0 @@
use crate::cell::UnsafeCell;
use crate::intrinsics::{atomic_cxchg, atomic_load, atomic_xadd, atomic_xchg};
use crate::ptr;
use crate::time::Duration;
use crate::sys::mutex::{mutex_unlock, Mutex};
use crate::sys::syscall::{futex, TimeSpec, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE};
pub struct Condvar {
lock: UnsafeCell<*mut i32>,
seq: UnsafeCell<i32>
}
impl Condvar {
pub const fn new() -> Condvar {
Condvar {
lock: UnsafeCell::new(ptr::null_mut()),
seq: UnsafeCell::new(0)
}
}
#[inline]
pub unsafe fn init(&self) {
*self.lock.get() = ptr::null_mut();
*self.seq.get() = 0;
}
#[inline]
pub fn notify_one(&self) {
unsafe {
let seq = self.seq.get();
atomic_xadd(seq, 1);
let _ = futex(seq, FUTEX_WAKE, 1, 0, ptr::null_mut());
}
}
#[inline]
pub fn notify_all(&self) {
unsafe {
let lock = self.lock.get();
let seq = self.seq.get();
if *lock == ptr::null_mut() {
return;
}
atomic_xadd(seq, 1);
let _ = futex(seq, FUTEX_REQUEUE, 1, crate::usize::MAX, *lock);
}
}
#[inline]
unsafe fn wait_inner(&self, mutex: &Mutex, timeout_ptr: *const TimeSpec) -> bool {
let lock = self.lock.get();
let seq = self.seq.get();
if *lock != mutex.lock.get() {
if *lock != ptr::null_mut() {
panic!("Condvar used with more than one Mutex");
}
atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize);
}
mutex_unlock(*lock);
let seq_before = atomic_load(seq);
let _ = futex(seq, FUTEX_WAIT, seq_before, timeout_ptr as usize, ptr::null_mut());
let seq_after = atomic_load(seq);
while atomic_xchg(*lock, 2) != 0 {
let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut());
}
seq_before != seq_after
}
#[inline]
pub fn wait(&self, mutex: &Mutex) {
unsafe {
assert!(self.wait_inner(mutex, ptr::null()));
}
}
#[inline]
pub fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
unsafe {
let timeout = TimeSpec {
tv_sec: dur.as_secs() as i64,
tv_nsec: dur.subsec_nanos() as i32
};
self.wait_inner(mutex, &timeout as *const TimeSpec)
}
}
#[inline]
pub unsafe fn destroy(&self) {
*self.lock.get() = ptr::null_mut();
*self.seq.get() = 0;
}
}
unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}

View File

@ -1,9 +0,0 @@
pub mod os {
pub const FAMILY: &str = "redox";
pub const OS: &str = "redox";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}

View File

@ -1,38 +0,0 @@
//! Redox-specific extension to the primitives in the `std::ffi` module.
//!
//! # Examples
//!
//! ```
//! use std::ffi::OsString;
//! use std::os::redox::ffi::OsStringExt;
//!
//! let bytes = b"foo".to_vec();
//!
//! // OsStringExt::from_vec
//! let os_string = OsString::from_vec(bytes);
//! assert_eq!(os_string.to_str(), Some("foo"));
//!
//! // OsStringExt::into_vec
//! let bytes = os_string.into_vec();
//! assert_eq!(bytes, b"foo");
//! ```
//!
//! ```
//! use std::ffi::OsStr;
//! use std::os::redox::ffi::OsStrExt;
//!
//! let bytes = b"foo";
//!
//! // OsStrExt::from_bytes
//! let os_str = OsStr::from_bytes(bytes);
//! assert_eq!(os_str.to_str(), Some("foo"));
//!
//! // OsStrExt::as_bytes
//! let bytes = os_str.as_bytes();
//! assert_eq!(bytes, b"foo");
//! ```
#![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::sys_common::os_str_bytes::*;

View File

@ -1,339 +0,0 @@
//! Redox-specific extensions to primitives in the `std::fs` module.
#![stable(feature = "rust1", since = "1.0.0")]
use crate::fs::{self, Permissions, OpenOptions};
use crate::io;
use crate::path::Path;
use crate::sys;
use crate::sys_common::{FromInner, AsInner, AsInnerMut};
/// Redox-specific extensions to [`fs::Permissions`].
///
/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait PermissionsExt {
/// Returns the underlying raw `mode_t` bits that are the standard Redox
/// permissions for this file.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
/// use std::os::redox::fs::PermissionsExt;
///
/// fn main() -> std::io::Result<()> {
/// let f = File::create("foo.txt")?;
/// let metadata = f.metadata()?;
/// let permissions = metadata.permissions();
///
/// println!("permissions: {:o}", permissions.mode());
/// Ok(())
/// }
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&self) -> u32;
/// Sets the underlying raw bits for this set of permissions.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
/// use std::os::redox::fs::PermissionsExt;
///
/// fn main() -> std::io::Result<()> {
/// let f = File::create("foo.txt")?;
/// let metadata = f.metadata()?;
/// let mut permissions = metadata.permissions();
///
/// permissions.set_mode(0o644); // Read/write for owner and read for others.
/// assert_eq!(permissions.mode(), 0o644);
/// Ok(())
/// }
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn set_mode(&mut self, mode: u32);
/// Creates a new instance of `Permissions` from the given set of Redox
/// permission bits.
///
/// # Examples
///
/// ```
/// use std::fs::Permissions;
/// use std::os::redox::fs::PermissionsExt;
///
/// // Read/write for owner and read for others.
/// let permissions = Permissions::from_mode(0o644);
/// assert_eq!(permissions.mode(), 0o644);
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn from_mode(mode: u32) -> Self;
}
#[stable(feature = "fs_ext", since = "1.1.0")]
impl PermissionsExt for Permissions {
fn mode(&self) -> u32 {
self.as_inner().mode()
}
fn set_mode(&mut self, mode: u32) {
*self = Permissions::from_inner(FromInner::from_inner(mode));
}
fn from_mode(mode: u32) -> Permissions {
Permissions::from_inner(FromInner::from_inner(mode))
}
}
/// Redox-specific extensions to [`fs::OpenOptions`].
///
/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait OpenOptionsExt {
/// Sets the mode bits that a new file will be created with.
///
/// If a new file is created as part of a `File::open_opts` call then this
/// specified `mode` will be used as the permission bits for the new file.
/// If no `mode` is set, the default of `0o666` will be used.
/// The operating system masks out bits with the systems `umask`, to produce
/// the final permissions.
///
/// # Examples
///
/// ```no_run
/// # #![feature(libc)]
/// extern crate libc;
/// use std::fs::OpenOptions;
/// use std::os::redox::fs::OpenOptionsExt;
///
/// # fn main() {
/// let mut options = OpenOptions::new();
/// options.mode(0o644); // Give read/write for owner and read for others.
/// let file = options.open("foo.txt");
/// # }
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&mut self, mode: u32) -> &mut Self;
/// Passes custom flags to the `flags` argument of `open`.
///
/// The bits that define the access mode are masked out with `O_ACCMODE`, to
/// ensure they do not interfere with the access mode set by Rusts options.
///
/// Custom flags can only set flags, not remove flags set by Rusts options.
/// This options overwrites any previously set custom flags.
///
/// # Examples
///
/// ```no_run
/// # #![feature(libc)]
/// extern crate libc;
/// use std::fs::OpenOptions;
/// use std::os::redox::fs::OpenOptionsExt;
///
/// # fn main() {
/// let mut options = OpenOptions::new();
/// options.write(true);
/// if cfg!(target_os = "redox") {
/// options.custom_flags(libc::O_NOFOLLOW);
/// }
/// let file = options.open("foo.txt");
/// # }
/// ```
#[stable(feature = "open_options_ext", since = "1.10.0")]
fn custom_flags(&mut self, flags: i32) -> &mut Self;
}
#[stable(feature = "fs_ext", since = "1.1.0")]
impl OpenOptionsExt for OpenOptions {
fn mode(&mut self, mode: u32) -> &mut OpenOptions {
self.as_inner_mut().mode(mode); self
}
fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
self.as_inner_mut().custom_flags(flags); self
}
}
/// Redox-specific extensions to [`fs::Metadata`].
///
/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn dev(&self) -> u64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn ino(&self) -> u64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn mode(&self) -> u32;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn nlink(&self) -> u64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn uid(&self) -> u32;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn gid(&self) -> u32;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn size(&self) -> u64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn atime(&self) -> i64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn atime_nsec(&self) -> i64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn mtime(&self) -> i64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn mtime_nsec(&self) -> i64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn ctime(&self) -> i64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn ctime_nsec(&self) -> i64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn blksize(&self) -> u64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn blocks(&self) -> u64;
}
// Hm, why are there casts here to the returned type, shouldn't the types always
// be the same? Right you are! Turns out, however, on android at least the types
// in the raw `stat` structure are not the same as the types being returned. Who
// knew!
//
// As a result to make sure this compiles for all platforms we do the manual
// casts and rely on manual lowering to `stat` if the raw type is desired.
#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for fs::Metadata {
fn dev(&self) -> u64 {
self.as_inner().as_inner().st_dev as u64
}
fn ino(&self) -> u64 {
self.as_inner().as_inner().st_ino as u64
}
fn mode(&self) -> u32 {
self.as_inner().as_inner().st_mode as u32
}
fn nlink(&self) -> u64 {
self.as_inner().as_inner().st_nlink as u64
}
fn uid(&self) -> u32 {
self.as_inner().as_inner().st_uid as u32
}
fn gid(&self) -> u32 {
self.as_inner().as_inner().st_gid as u32
}
fn size(&self) -> u64 {
self.as_inner().as_inner().st_size as u64
}
fn atime(&self) -> i64 {
self.as_inner().as_inner().st_atime as i64
}
fn atime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_atime_nsec as i64
}
fn mtime(&self) -> i64 {
self.as_inner().as_inner().st_mtime as i64
}
fn mtime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_mtime_nsec as i64
}
fn ctime(&self) -> i64 {
self.as_inner().as_inner().st_ctime as i64
}
fn ctime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_ctime_nsec as i64
}
fn blksize(&self) -> u64 {
self.as_inner().as_inner().st_blksize as u64
}
fn blocks(&self) -> u64 {
self.as_inner().as_inner().st_blocks as u64
}
}
/// Redox-specific extensions for [`FileType`].
///
/// Adds support for special Unix file types such as block/character devices,
/// pipes, and sockets.
///
/// [`FileType`]: ../../../../std/fs/struct.FileType.html
#[stable(feature = "file_type_ext", since = "1.5.0")]
pub trait FileTypeExt {
/// Returns whether this file type is a block device.
#[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_block_device(&self) -> bool;
/// Returns whether this file type is a char device.
#[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_char_device(&self) -> bool;
/// Returns whether this file type is a fifo.
#[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_fifo(&self) -> bool;
/// Returns whether this file type is a socket.
#[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_socket(&self) -> bool;
}
#[stable(feature = "file_type_ext", since = "1.5.0")]
impl FileTypeExt for fs::FileType {
fn is_block_device(&self) -> bool { false /*FIXME: Implement block device mode*/ }
fn is_char_device(&self) -> bool { false /*FIXME: Implement char device mode*/ }
fn is_fifo(&self) -> bool { false /*FIXME: Implement fifo mode*/ }
fn is_socket(&self) -> bool { false /*FIXME: Implement socket mode*/ }
}
/// Creates a new symbolic link on the filesystem.
///
/// The `dst` path will be a symbolic link pointing to the `src` path.
///
/// # Note
///
/// On Windows, you must specify whether a symbolic link points to a file
/// or directory. Use `os::windows::fs::symlink_file` to create a
/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
/// symbolic link to a directory. Additionally, the process must have
/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
/// symbolic link.
///
/// # Examples
///
/// ```no_run
/// use std::os::redox::fs;
///
/// fn main() -> std::io::Result<()> {
/// fs::symlink("a.txt", "b.txt")?;
/// Ok(())
/// }
/// ```
#[stable(feature = "symlink", since = "1.1.0")]
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
{
sys::fs::symlink(src.as_ref(), dst.as_ref())
}
/// Redox-specific extensions to [`fs::DirBuilder`].
///
/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
#[stable(feature = "dir_builder", since = "1.6.0")]
pub trait DirBuilderExt {
/// Sets the mode to create new directories with. This option defaults to
/// 0o777.
///
/// # Examples
///
/// ```no_run
/// use std::fs::DirBuilder;
/// use std::os::redox::fs::DirBuilderExt;
///
/// let mut builder = DirBuilder::new();
/// builder.mode(0o755);
/// ```
#[stable(feature = "dir_builder", since = "1.6.0")]
fn mode(&mut self, mode: u32) -> &mut Self;
}
#[stable(feature = "dir_builder", since = "1.6.0")]
impl DirBuilderExt for fs::DirBuilder {
fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
self.as_inner_mut().set_mode(mode);
self
}
}

View File

@ -1,172 +0,0 @@
//! Unix-specific extensions to general I/O primitives
#![stable(feature = "rust1", since = "1.0.0")]
use crate::fs;
use crate::net;
use crate::sys;
use crate::io;
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
/// Raw file descriptors.
#[stable(feature = "rust1", since = "1.0.0")]
pub type RawFd = usize;
/// A trait to extract the raw unix file descriptor from an underlying
/// object.
///
/// This is only available on unix platforms and must be imported in order
/// to call the method. Windows platforms have a corresponding `AsRawHandle`
/// and `AsRawSocket` set of traits.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRawFd {
/// Extracts the raw file descriptor.
///
/// This method does **not** pass ownership of the raw file descriptor
/// to the caller. The descriptor is only guaranteed to be valid while
/// the original object has not yet been destroyed.
#[stable(feature = "rust1", since = "1.0.0")]
fn as_raw_fd(&self) -> RawFd;
}
/// A trait to express the ability to construct an object from a raw file
/// descriptor.
#[stable(feature = "from_raw_os", since = "1.1.0")]
pub trait FromRawFd {
/// Constructs a new instances of `Self` from the given raw file
/// descriptor.
///
/// This function **consumes ownership** of the specified file
/// descriptor. The returned object will take responsibility for closing
/// it when the object goes out of scope.
///
/// This function is also unsafe as the primitives currently returned
/// have the contract that they are the sole owner of the file
/// descriptor they are wrapping. Usage of this function could
/// accidentally allow violating this contract which can cause memory
/// unsafety in code that relies on it being true.
#[stable(feature = "from_raw_os", since = "1.1.0")]
unsafe fn from_raw_fd(fd: RawFd) -> Self;
}
/// A trait to express the ability to consume an object and acquire ownership of
/// its raw file descriptor.
#[stable(feature = "into_raw_os", since = "1.4.0")]
pub trait IntoRawFd {
/// Consumes this object, returning the raw underlying file descriptor.
///
/// This function **transfers ownership** of the underlying file descriptor
/// to the caller. Callers are then the unique owners of the file descriptor
/// and must close the descriptor once it's no longer needed.
#[stable(feature = "into_raw_os", since = "1.4.0")]
fn into_raw_fd(self) -> RawFd;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for fs::File {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd().raw()
}
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawFd for fs::File {
unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
fs::File::from_inner(sys::fs::File::from_inner(fd))
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for fs::File {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_fd().into_raw()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::TcpStream {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().as_inner().fd().raw()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::TcpListener {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().as_inner().fd().raw()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::UdpSocket {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().as_inner().fd().raw()
}
}
#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawFd for io::Stdin {
fn as_raw_fd(&self) -> RawFd { 0 }
}
#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawFd for io::Stdout {
fn as_raw_fd(&self) -> RawFd { 1 }
}
#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawFd for io::Stderr {
fn as_raw_fd(&self) -> RawFd { 2 }
}
#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
impl<'a> AsRawFd for io::StdinLock<'a> {
fn as_raw_fd(&self) -> RawFd { 0 }
}
#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
impl<'a> AsRawFd for io::StdoutLock<'a> {
fn as_raw_fd(&self) -> RawFd { 1 }
}
#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
impl<'a> AsRawFd for io::StderrLock<'a> {
fn as_raw_fd(&self) -> RawFd { 2 }
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawFd for net::TcpStream {
unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
let file = sys::fs::File::from_inner(fd);
net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(file))
}
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawFd for net::TcpListener {
unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
let file = sys::fs::File::from_inner(fd);
net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(file))
}
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawFd for net::UdpSocket {
unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
let file = sys::fs::File::from_inner(fd);
net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(file))
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for net::TcpStream {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_inner().into_fd().into_raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for net::TcpListener {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_inner().into_fd().into_raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for net::UdpSocket {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_inner().into_fd().into_raw()
}
}

View File

@ -1,45 +0,0 @@
//! Experimental extensions to `std` for Unix platforms.
//!
//! For now, this module is limited to extracting file descriptors,
//! but its functionality will grow over time.
//!
//! # Examples
//!
//! ```no_run
//! use std::fs::File;
//! use std::os::unix::prelude::*;
//!
//! fn main() {
//! let f = File::create("foo.txt").unwrap();
//! let fd = f.as_raw_fd();
//!
//! // use fd with native unix bindings
//! }
//! ```
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(cfg(target_os = "redox"))]
pub mod ffi;
pub mod fs;
pub mod io;
pub mod net;
pub mod process;
pub mod thread;
/// A prelude for conveniently writing platform-specific code.
///
/// Includes all extension traits, and some important type definitions.
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::ffi::{OsStrExt, OsStringExt};
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::fs::{FileTypeExt, PermissionsExt, OpenOptionsExt, MetadataExt};
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::thread::JoinHandleExt;
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::process::{CommandExt, ExitStatusExt};
}

View File

@ -1,759 +0,0 @@
#![stable(feature = "unix_socket_redox", since = "1.29.0")]
//! Unix-specific networking functionality
use crate::fmt;
use crate::io::{self, Error, ErrorKind, Initializer};
use crate::net::Shutdown;
use crate::os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
use crate::path::Path;
use crate::time::Duration;
use crate::sys::{cvt, fd::FileDesc, syscall};
/// An address associated with a Unix socket.
///
/// # Examples
///
/// ```
/// use std::os::unix::net::UnixListener;
///
/// let socket = match UnixListener::bind("/tmp/sock") {
/// Ok(sock) => sock,
/// Err(e) => {
/// println!("Couldn't bind: {:?}", e);
/// return
/// }
/// };
/// let addr = socket.local_addr().expect("Couldn't get local address");
/// ```
#[derive(Clone)]
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub struct SocketAddr(());
impl SocketAddr {
/// Returns the contents of this address if it is a `pathname` address.
///
/// # Examples
///
/// With a pathname:
///
/// ```no_run
/// use std::os::unix::net::UnixListener;
/// use std::path::Path;
///
/// let socket = UnixListener::bind("/tmp/sock").unwrap();
/// let addr = socket.local_addr().expect("Couldn't get local address");
/// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
/// ```
///
/// Without a pathname:
///
/// ```
/// use std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::unbound().unwrap();
/// let addr = socket.local_addr().expect("Couldn't get local address");
/// assert_eq!(addr.as_pathname(), None);
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn as_pathname(&self) -> Option<&Path> {
None
}
/// Returns `true` if the address is unnamed.
///
/// # Examples
///
/// A named address:
///
/// ```no_run
/// use std::os::unix::net::UnixListener;
///
/// let socket = UnixListener::bind("/tmp/sock").unwrap();
/// let addr = socket.local_addr().expect("Couldn't get local address");
/// assert_eq!(addr.is_unnamed(), false);
/// ```
///
/// An unnamed address:
///
/// ```
/// use std::os::unix::net::UnixDatagram;
///
/// let socket = UnixDatagram::unbound().unwrap();
/// let addr = socket.local_addr().expect("Couldn't get local address");
/// assert_eq!(addr.is_unnamed(), true);
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn is_unnamed(&self) -> bool {
false
}
}
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
impl fmt::Debug for SocketAddr {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "SocketAddr")
}
}
/// A Unix stream socket.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixStream;
/// use std::io::prelude::*;
///
/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap();
/// stream.write_all(b"hello world").unwrap();
/// let mut response = String::new();
/// stream.read_to_string(&mut response).unwrap();
/// println!("{}", response);
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub struct UnixStream(FileDesc);
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
impl fmt::Debug for UnixStream {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut builder = fmt.debug_struct("UnixStream");
builder.field("fd", &self.0.raw());
if let Ok(addr) = self.local_addr() {
builder.field("local", &addr);
}
if let Ok(addr) = self.peer_addr() {
builder.field("peer", &addr);
}
builder.finish()
}
}
impl UnixStream {
/// Connects to the socket named by `path`.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixStream;
///
/// let socket = match UnixStream::connect("/tmp/sock") {
/// Ok(sock) => sock,
/// Err(e) => {
/// println!("Couldn't connect: {:?}", e);
/// return
/// }
/// };
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
if let Some(s) = path.as_ref().to_str() {
cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC))
.map(FileDesc::new)
.map(UnixStream)
} else {
Err(Error::new(
ErrorKind::Other,
"UnixStream::connect: non-utf8 paths not supported on redox"
))
}
}
/// Creates an unnamed pair of connected sockets.
///
/// Returns two `UnixStream`s which are connected to each other.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixStream;
///
/// let (sock1, sock2) = match UnixStream::pair() {
/// Ok((sock1, sock2)) => (sock1, sock2),
/// Err(e) => {
/// println!("Couldn't create a pair of sockets: {:?}", e);
/// return
/// }
/// };
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC))
.map(FileDesc::new)?;
let client = server.duplicate_path(b"connect")?;
let stream = server.duplicate_path(b"listen")?;
Ok((UnixStream(client), UnixStream(stream)))
}
/// Creates a new independently owned handle to the underlying socket.
///
/// The returned `UnixStream` is a reference to the same stream that this
/// object references. Both handles will read and write the same stream of
/// data, and options set on one stream will be propagated to the other
/// stream.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixStream;
///
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
/// let sock_copy = socket.try_clone().expect("Couldn't clone socket");
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn try_clone(&self) -> io::Result<UnixStream> {
self.0.duplicate().map(UnixStream)
}
/// Returns the socket address of the local half of this connection.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixStream;
///
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
/// let addr = socket.local_addr().expect("Couldn't get local address");
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn local_addr(&self) -> io::Result<SocketAddr> {
Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox"))
}
/// Returns the socket address of the remote half of this connection.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixStream;
///
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
/// let addr = socket.peer_addr().expect("Couldn't get peer address");
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox"))
}
/// Sets the read timeout for the socket.
///
/// If the provided value is [`None`], then [`read`] calls will block
/// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
/// method.
///
/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
/// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
/// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read
/// [`Duration`]: ../../../../std/time/struct.Duration.html
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixStream;
/// use std::time::Duration;
///
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
/// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
/// ```
///
/// An [`Err`] is returned if the zero [`Duration`] is passed to this
/// method:
///
/// ```no_run
/// use std::io;
/// use std::os::unix::net::UnixStream;
/// use std::time::Duration;
///
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
/// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
/// let err = result.unwrap_err();
/// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn set_read_timeout(&self, _timeout: Option<Duration>) -> io::Result<()> {
Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox"))
}
/// Sets the write timeout for the socket.
///
/// If the provided value is [`None`], then [`write`] calls will block
/// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
/// passed to this method.
///
/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
/// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
/// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write
/// [`Duration`]: ../../../../std/time/struct.Duration.html
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixStream;
/// use std::time::Duration;
///
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
/// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
/// ```
///
/// An [`Err`] is returned if the zero [`Duration`] is passed to this
/// method:
///
/// ```no_run
/// use std::io;
/// use std::net::UdpSocket;
/// use std::time::Duration;
///
/// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap();
/// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
/// let err = result.unwrap_err();
/// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn set_write_timeout(&self, _timeout: Option<Duration>) -> io::Result<()> {
Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox"))
}
/// Returns the read timeout of this socket.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixStream;
/// use std::time::Duration;
///
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
/// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
/// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0)));
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox"))
}
/// Returns the write timeout of this socket.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixStream;
/// use std::time::Duration;
///
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
/// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
/// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0)));
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox"))
}
/// Moves the socket into or out of nonblocking mode.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixStream;
///
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
/// socket.set_nonblocking(true).expect("Couldn't set nonblocking");
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
self.0.set_nonblocking(nonblocking)
}
/// Returns the value of the `SO_ERROR` option.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixStream;
///
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
/// if let Ok(Some(err)) = socket.take_error() {
/// println!("Got error: {:?}", err);
/// }
/// ```
///
/// # Platform specific
/// On Redox this always returns `None`.
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
Ok(None)
}
/// Shuts down the read, write, or both halves of this connection.
///
/// This function will cause all pending and future I/O calls on the
/// specified portions to immediately return with an appropriate value
/// (see the documentation of [`Shutdown`]).
///
/// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixStream;
/// use std::net::Shutdown;
///
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
/// socket.shutdown(Shutdown::Both).expect("shutdown function failed");
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> {
Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox"))
}
}
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
impl io::Read for UnixStream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
io::Read::read(&mut &*self, buf)
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
}
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
impl<'a> io::Read for &'a UnixStream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
}
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
impl io::Write for UnixStream {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
io::Write::write(&mut &*self, buf)
}
fn flush(&mut self) -> io::Result<()> {
io::Write::flush(&mut &*self)
}
}
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
impl<'a> io::Write for &'a UnixStream {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
impl AsRawFd for UnixStream {
fn as_raw_fd(&self) -> RawFd {
self.0.raw()
}
}
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
impl FromRawFd for UnixStream {
unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
UnixStream(FileDesc::new(fd))
}
}
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
impl IntoRawFd for UnixStream {
fn into_raw_fd(self) -> RawFd {
self.0.into_raw()
}
}
/// A structure representing a Unix domain socket server.
///
/// # Examples
///
/// ```no_run
/// use std::thread;
/// use std::os::unix::net::{UnixStream, UnixListener};
///
/// fn handle_client(stream: UnixStream) {
/// // ...
/// }
///
/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
///
/// // accept connections and process them, spawning a new thread for each one
/// for stream in listener.incoming() {
/// match stream {
/// Ok(stream) => {
/// /* connection succeeded */
/// thread::spawn(|| handle_client(stream));
/// }
/// Err(err) => {
/// /* connection failed */
/// break;
/// }
/// }
/// }
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub struct UnixListener(FileDesc);
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
impl fmt::Debug for UnixListener {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut builder = fmt.debug_struct("UnixListener");
builder.field("fd", &self.0.raw());
if let Ok(addr) = self.local_addr() {
builder.field("local", &addr);
}
builder.finish()
}
}
impl UnixListener {
/// Creates a new `UnixListener` bound to the specified socket.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixListener;
///
/// let listener = match UnixListener::bind("/path/to/the/socket") {
/// Ok(sock) => sock,
/// Err(e) => {
/// println!("Couldn't connect: {:?}", e);
/// return
/// }
/// };
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
if let Some(s) = path.as_ref().to_str() {
cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC))
.map(FileDesc::new)
.map(UnixListener)
} else {
Err(Error::new(
ErrorKind::Other,
"UnixListener::bind: non-utf8 paths not supported on redox"
))
}
}
/// Accepts a new incoming connection to this listener.
///
/// This function will block the calling thread until a new Unix connection
/// is established. When established, the corresponding [`UnixStream`] and
/// the remote peer's address will be returned.
///
/// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixListener;
///
/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
///
/// match listener.accept() {
/// Ok((socket, addr)) => println!("Got a client: {:?}", addr),
/// Err(e) => println!("accept function failed: {:?}", e),
/// }
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(())))
}
/// Creates a new independently owned handle to the underlying socket.
///
/// The returned `UnixListener` is a reference to the same socket that this
/// object references. Both handles can be used to accept incoming
/// connections and options set on one listener will affect the other.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixListener;
///
/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
///
/// let listener_copy = listener.try_clone().expect("try_clone failed");
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn try_clone(&self) -> io::Result<UnixListener> {
self.0.duplicate().map(UnixListener)
}
/// Returns the local socket address of this listener.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixListener;
///
/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
///
/// let addr = listener.local_addr().expect("Couldn't get local address");
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn local_addr(&self) -> io::Result<SocketAddr> {
Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox"))
}
/// Moves the socket into or out of nonblocking mode.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixListener;
///
/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
///
/// listener.set_nonblocking(true).expect("Couldn't set non blocking");
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
self.0.set_nonblocking(nonblocking)
}
/// Returns the value of the `SO_ERROR` option.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::net::UnixListener;
///
/// let listener = UnixListener::bind("/tmp/sock").unwrap();
///
/// if let Ok(Some(err)) = listener.take_error() {
/// println!("Got error: {:?}", err);
/// }
/// ```
///
/// # Platform specific
/// On Redox this always returns `None`.
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
Ok(None)
}
/// Returns an iterator over incoming connections.
///
/// The iterator will never return [`None`] and will also not yield the
/// peer's [`SocketAddr`] structure.
///
/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
/// [`SocketAddr`]: struct.SocketAddr.html
///
/// # Examples
///
/// ```no_run
/// use std::thread;
/// use std::os::unix::net::{UnixStream, UnixListener};
///
/// fn handle_client(stream: UnixStream) {
/// // ...
/// }
///
/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
///
/// for stream in listener.incoming() {
/// match stream {
/// Ok(stream) => {
/// thread::spawn(|| handle_client(stream));
/// }
/// Err(err) => {
/// break;
/// }
/// }
/// }
/// ```
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub fn incoming(&self) -> Incoming<'_> {
Incoming { listener: self }
}
}
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
impl AsRawFd for UnixListener {
fn as_raw_fd(&self) -> RawFd {
self.0.raw()
}
}
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
impl FromRawFd for UnixListener {
unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
UnixListener(FileDesc::new(fd))
}
}
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
impl IntoRawFd for UnixListener {
fn into_raw_fd(self) -> RawFd {
self.0.into_raw()
}
}
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
impl<'a> IntoIterator for &'a UnixListener {
type Item = io::Result<UnixStream>;
type IntoIter = Incoming<'a>;
fn into_iter(self) -> Incoming<'a> {
self.incoming()
}
}
/// An iterator over incoming connections to a [`UnixListener`].
///
/// It will never return [`None`].
///
/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
/// [`UnixListener`]: struct.UnixListener.html
///
/// # Examples
///
/// ```no_run
/// use std::thread;
/// use std::os::unix::net::{UnixStream, UnixListener};
///
/// fn handle_client(stream: UnixStream) {
/// // ...
/// }
///
/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
///
/// for stream in listener.incoming() {
/// match stream {
/// Ok(stream) => {
/// thread::spawn(|| handle_client(stream));
/// }
/// Err(err) => {
/// break;
/// }
/// }
/// }
/// ```
#[derive(Debug)]
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
pub struct Incoming<'a> {
listener: &'a UnixListener,
}
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
impl<'a> Iterator for Incoming<'a> {
type Item = io::Result<UnixStream>;
fn next(&mut self) -> Option<io::Result<UnixStream>> {
Some(self.listener.accept().map(|s| s.0))
}
fn size_hint(&self) -> (usize, Option<usize>) {
(usize::max_value(), None)
}
}

View File

@ -1,197 +0,0 @@
//! Redox-specific extensions to primitives in the `std::process` module.
#![stable(feature = "rust1", since = "1.0.0")]
use crate::io;
use crate::os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
use crate::process;
use crate::sys;
use crate::sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
/// Redox-specific extensions to the [`process::Command`] builder,
///
/// [`process::Command`]: ../../../../std/process/struct.Command.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait CommandExt {
/// Sets the child process's user ID. This translates to a
/// `setuid` call in the child process. Failure in the `setuid`
/// call will cause the spawn to fail.
#[stable(feature = "rust1", since = "1.0.0")]
fn uid(&mut self, id: u32) -> &mut process::Command;
/// Similar to `uid`, but sets the group ID of the child process. This has
/// the same semantics as the `uid` field.
#[stable(feature = "rust1", since = "1.0.0")]
fn gid(&mut self, id: u32) -> &mut process::Command;
/// Schedules a closure to be run just before the `exec` function is
/// invoked.
///
/// The closure is allowed to return an I/O error whose OS error code will
/// be communicated back to the parent and returned as an error from when
/// the spawn was requested.
///
/// Multiple closures can be registered and they will be called in order of
/// their registration. If a closure returns `Err` then no further closures
/// will be called and the spawn operation will immediately return with a
/// failure.
///
/// # Notes and Safety
///
/// This closure will be run in the context of the child process after a
/// `fork`. This primarily means that any modifications made to memory on
/// behalf of this closure will **not** be visible to the parent process.
/// This is often a very constrained environment where normal operations
/// like `malloc` or acquiring a mutex are not guaranteed to work (due to
/// other threads perhaps still running when the `fork` was run).
///
/// This also means that all resources such as file descriptors and
/// memory-mapped regions got duplicated. It is your responsibility to make
/// sure that the closure does not violate library invariants by making
/// invalid use of these duplicates.
///
/// When this closure is run, aspects such as the stdio file descriptors and
/// working directory have successfully been changed, so output to these
/// locations may not appear where intended.
#[stable(feature = "process_pre_exec", since = "1.34.0")]
unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
where F: FnMut() -> io::Result<()> + Send + Sync + 'static;
/// Schedules a closure to be run just before the `exec` function is
/// invoked.
///
/// This method is stable and usable, but it should be unsafe. To fix
/// that, it got deprecated in favor of the unsafe [`pre_exec`].
///
/// [`pre_exec`]: #tymethod.pre_exec
#[stable(feature = "process_exec", since = "1.15.0")]
#[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
fn before_exec<F>(&mut self, f: F) -> &mut process::Command
where F: FnMut() -> io::Result<()> + Send + Sync + 'static
{
unsafe { self.pre_exec(f) }
}
/// Performs all the required setup by this `Command`, followed by calling
/// the `execvp` syscall.
///
/// On success this function will not return, and otherwise it will return
/// an error indicating why the exec (or another part of the setup of the
/// `Command`) failed.
///
/// This function, unlike `spawn`, will **not** `fork` the process to create
/// a new child. Like spawn, however, the default behavior for the stdio
/// descriptors will be to inherited from the current process.
///
/// # Notes
///
/// The process may be in a "broken state" if this function returns in
/// error. For example the working directory, environment variables, signal
/// handling settings, various user/group information, or aspects of stdio
/// file descriptors may have changed. If a "transactional spawn" is
/// required to gracefully handle errors it is recommended to use the
/// cross-platform `spawn` instead.
#[stable(feature = "process_exec2", since = "1.9.0")]
fn exec(&mut self) -> io::Error;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl CommandExt for process::Command {
fn uid(&mut self, id: u32) -> &mut process::Command {
self.as_inner_mut().uid(id);
self
}
fn gid(&mut self, id: u32) -> &mut process::Command {
self.as_inner_mut().gid(id);
self
}
unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
where F: FnMut() -> io::Result<()> + Send + Sync + 'static
{
self.as_inner_mut().pre_exec(Box::new(f));
self
}
fn exec(&mut self) -> io::Error {
self.as_inner_mut().exec(sys::process::Stdio::Inherit)
}
}
/// Redox-specific extensions to [`process::ExitStatus`].
///
/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ExitStatusExt {
/// Creates a new `ExitStatus` from the raw underlying `i32` return value of
/// a process.
#[stable(feature = "exit_status_from", since = "1.12.0")]
fn from_raw(raw: i32) -> Self;
/// If the process was terminated by a signal, returns that signal.
#[stable(feature = "rust1", since = "1.0.0")]
fn signal(&self) -> Option<i32>;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ExitStatusExt for process::ExitStatus {
fn from_raw(raw: i32) -> Self {
process::ExitStatus::from_inner(From::from(raw))
}
fn signal(&self) -> Option<i32> {
self.as_inner().signal()
}
}
#[stable(feature = "process_extensions", since = "1.2.0")]
impl FromRawFd for process::Stdio {
unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
let fd = sys::fd::FileDesc::new(fd);
let io = sys::process::Stdio::Fd(fd);
process::Stdio::from_inner(io)
}
}
#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStdin {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd().raw()
}
}
#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStdout {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd().raw()
}
}
#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStderr {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd().raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStdin {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_fd().into_raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStdout {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_fd().into_raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStderr {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_fd().into_raw()
}
}

View File

@ -1,39 +0,0 @@
//! Redox-specific extensions to primitives in the `std::thread` module.
#![stable(feature = "thread_extensions", since = "1.9.0")]
use crate::sys_common::{AsInner, IntoInner};
use crate::thread::JoinHandle;
#[stable(feature = "thread_extensions", since = "1.9.0")]
#[allow(deprecated)]
pub type RawPthread = usize;
/// Redox-specific extensions to [`thread::JoinHandle`].
///
/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
#[stable(feature = "thread_extensions", since = "1.9.0")]
pub trait JoinHandleExt {
/// Extracts the raw pthread_t without taking ownership
#[stable(feature = "thread_extensions", since = "1.9.0")]
fn as_pthread_t(&self) -> RawPthread;
/// Consumes the thread, returning the raw pthread_t
///
/// This function **transfers ownership** of the underlying pthread_t to
/// the caller. Callers are then the unique owners of the pthread_t and
/// must either detach or join the pthread_t once it's no longer needed.
#[stable(feature = "thread_extensions", since = "1.9.0")]
fn into_pthread_t(self) -> RawPthread;
}
#[stable(feature = "thread_extensions", since = "1.9.0")]
impl<T> JoinHandleExt for JoinHandle<T> {
fn as_pthread_t(&self) -> RawPthread {
self.as_inner().id() as RawPthread
}
fn into_pthread_t(self) -> RawPthread {
self.into_inner().into_id() as RawPthread
}
}

View File

@ -1,4 +0,0 @@
#![cfg(target_thread_local)]
#![unstable(feature = "thread_local_internals", issue = "0")]
pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor;

View File

@ -1,88 +0,0 @@
#![unstable(reason = "not public", issue = "0", feature = "fd")]
use crate::io::{self, Read};
use crate::mem;
use crate::sys::{cvt, syscall};
use crate::sys_common::AsInner;
pub struct FileDesc {
fd: usize,
}
impl FileDesc {
pub fn new(fd: usize) -> FileDesc {
FileDesc { fd }
}
pub fn raw(&self) -> usize { self.fd }
/// Extracts the actual file descriptor without closing it.
pub fn into_raw(self) -> usize {
let fd = self.fd;
mem::forget(self);
fd
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
cvt(syscall::read(self.fd, buf))
}
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
let mut me = self;
(&mut me).read_to_end(buf)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
cvt(syscall::write(self.fd, buf))
}
pub fn duplicate(&self) -> io::Result<FileDesc> {
self.duplicate_path(&[])
}
pub fn duplicate_path(&self, path: &[u8]) -> io::Result<FileDesc> {
let new_fd = cvt(syscall::dup(self.fd, path))?;
Ok(FileDesc::new(new_fd))
}
pub fn nonblocking(&self) -> io::Result<bool> {
let flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?;
Ok(flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK)
}
pub fn set_cloexec(&self) -> io::Result<()> {
let mut flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFD, 0))?;
flags |= syscall::O_CLOEXEC;
cvt(syscall::fcntl(self.fd, syscall::F_SETFD, flags)).and(Ok(()))
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
let mut flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?;
if nonblocking {
flags |= syscall::O_NONBLOCK;
} else {
flags &= !syscall::O_NONBLOCK;
}
cvt(syscall::fcntl(self.fd, syscall::F_SETFL, flags)).and(Ok(()))
}
}
impl<'a> Read for &'a FileDesc {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
}
impl AsInner<usize> for FileDesc {
fn as_inner(&self) -> &usize { &self.fd }
}
impl Drop for FileDesc {
fn drop(&mut self) {
// Note that errors are ignored when closing a file descriptor. The
// reason for this is that if an error occurs we don't actually know if
// the file descriptor was closed or not, and if we retried (for
// something like EINTR), we might close another valid file descriptor
// (opened after we closed ours.
let _ = syscall::close(self.fd);
}
}

View File

@ -1,447 +0,0 @@
use crate::os::unix::prelude::*;
use crate::ffi::{OsString, OsStr};
use crate::fmt;
use crate::io::{self, Error, SeekFrom, IoSlice, IoSliceMut};
use crate::path::{Path, PathBuf};
use crate::sync::Arc;
use crate::sys::fd::FileDesc;
use crate::sys::time::SystemTime;
use crate::sys::{cvt, syscall};
use crate::sys_common::{AsInner, FromInner};
pub use crate::sys_common::fs::copy;
pub use crate::sys_common::fs::remove_dir_all;
pub struct File(FileDesc);
#[derive(Clone)]
pub struct FileAttr {
stat: syscall::Stat,
}
pub struct ReadDir {
data: Vec<u8>,
i: usize,
root: Arc<PathBuf>,
}
struct Dir(FileDesc);
unsafe impl Send for Dir {}
unsafe impl Sync for Dir {}
pub struct DirEntry {
root: Arc<PathBuf>,
name: Box<[u8]>
}
#[derive(Clone, Debug)]
pub struct OpenOptions {
// generic
read: bool,
write: bool,
append: bool,
truncate: bool,
create: bool,
create_new: bool,
// system-specific
custom_flags: i32,
mode: u16,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct FilePermissions { mode: u16 }
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct FileType { mode: u16 }
#[derive(Debug)]
pub struct DirBuilder { mode: u16 }
impl FileAttr {
pub fn size(&self) -> u64 { self.stat.st_size as u64 }
pub fn perm(&self) -> FilePermissions {
FilePermissions { mode: (self.stat.st_mode as u16) & 0o777 }
}
pub fn file_type(&self) -> FileType {
FileType { mode: self.stat.st_mode as u16 }
}
}
impl FileAttr {
pub fn modified(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(syscall::TimeSpec {
tv_sec: self.stat.st_mtime as i64,
tv_nsec: self.stat.st_mtime_nsec as i32,
}))
}
pub fn accessed(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(syscall::TimeSpec {
tv_sec: self.stat.st_atime as i64,
tv_nsec: self.stat.st_atime_nsec as i32,
}))
}
pub fn created(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(syscall::TimeSpec {
tv_sec: self.stat.st_ctime as i64,
tv_nsec: self.stat.st_ctime_nsec as i32,
}))
}
}
impl AsInner<syscall::Stat> for FileAttr {
fn as_inner(&self) -> &syscall::Stat { &self.stat }
}
impl FilePermissions {
pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 }
pub fn set_readonly(&mut self, readonly: bool) {
if readonly {
self.mode &= !0o222;
} else {
self.mode |= 0o222;
}
}
pub fn mode(&self) -> u32 { self.mode as u32 }
}
impl FileType {
pub fn is_dir(&self) -> bool { self.is(syscall::MODE_DIR) }
pub fn is_file(&self) -> bool { self.is(syscall::MODE_FILE) }
pub fn is_symlink(&self) -> bool { self.is(syscall::MODE_SYMLINK) }
pub fn is(&self, mode: u16) -> bool {
self.mode & syscall::MODE_TYPE == mode
}
}
impl FromInner<u32> for FilePermissions {
fn from_inner(mode: u32) -> FilePermissions {
FilePermissions { mode: mode as u16 }
}
}
impl fmt::Debug for ReadDir {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
// Thus the result will be e g 'ReadDir("/home")'
fmt::Debug::fmt(&*self.root, f)
}
}
impl Iterator for ReadDir {
type Item = io::Result<DirEntry>;
fn next(&mut self) -> Option<io::Result<DirEntry>> {
loop {
let start = self.i;
let mut i = self.i;
while i < self.data.len() {
self.i += 1;
if self.data[i] == b'\n' {
break;
}
i += 1;
}
if start < self.i {
let ret = DirEntry {
name: self.data[start .. i].to_owned().into_boxed_slice(),
root: self.root.clone()
};
if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
return Some(Ok(ret))
}
} else {
return None;
}
}
}
}
impl DirEntry {
pub fn path(&self) -> PathBuf {
self.root.join(OsStr::from_bytes(self.name_bytes()))
}
pub fn file_name(&self) -> OsString {
OsStr::from_bytes(self.name_bytes()).to_os_string()
}
pub fn metadata(&self) -> io::Result<FileAttr> {
lstat(&self.path())
}
pub fn file_type(&self) -> io::Result<FileType> {
lstat(&self.path()).map(|m| m.file_type())
}
fn name_bytes(&self) -> &[u8] {
&*self.name
}
}
impl OpenOptions {
pub fn new() -> OpenOptions {
OpenOptions {
// generic
read: false,
write: false,
append: false,
truncate: false,
create: false,
create_new: false,
// system-specific
custom_flags: 0,
mode: 0o666,
}
}
pub fn read(&mut self, read: bool) { self.read = read; }
pub fn write(&mut self, write: bool) { self.write = write; }
pub fn append(&mut self, append: bool) { self.append = append; }
pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
pub fn create(&mut self, create: bool) { self.create = create; }
pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
pub fn custom_flags(&mut self, flags: i32) { self.custom_flags = flags; }
pub fn mode(&mut self, mode: u32) { self.mode = mode as u16; }
fn get_access_mode(&self) -> io::Result<usize> {
match (self.read, self.write, self.append) {
(true, false, false) => Ok(syscall::O_RDONLY),
(false, true, false) => Ok(syscall::O_WRONLY),
(true, true, false) => Ok(syscall::O_RDWR),
(false, _, true) => Ok(syscall::O_WRONLY | syscall::O_APPEND),
(true, _, true) => Ok(syscall::O_RDWR | syscall::O_APPEND),
(false, false, false) => Err(Error::from_raw_os_error(syscall::EINVAL)),
}
}
fn get_creation_mode(&self) -> io::Result<usize> {
match (self.write, self.append) {
(true, false) => {}
(false, false) =>
if self.truncate || self.create || self.create_new {
return Err(Error::from_raw_os_error(syscall::EINVAL));
},
(_, true) =>
if self.truncate && !self.create_new {
return Err(Error::from_raw_os_error(syscall::EINVAL));
},
}
Ok(match (self.create, self.truncate, self.create_new) {
(false, false, false) => 0,
(true, false, false) => syscall::O_CREAT,
(false, true, false) => syscall::O_TRUNC,
(true, true, false) => syscall::O_CREAT | syscall::O_TRUNC,
(_, _, true) => syscall::O_CREAT | syscall::O_EXCL,
})
}
}
impl File {
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
let flags = syscall::O_CLOEXEC |
opts.get_access_mode()? as usize |
opts.get_creation_mode()? as usize |
(opts.custom_flags as usize & !syscall::O_ACCMODE);
let fd = cvt(syscall::open(path.to_str().unwrap(), flags | opts.mode as usize))?;
Ok(File(FileDesc::new(fd)))
}
pub fn file_attr(&self) -> io::Result<FileAttr> {
let mut stat = syscall::Stat::default();
cvt(syscall::fstat(self.0.raw(), &mut stat))?;
Ok(FileAttr { stat })
}
pub fn fsync(&self) -> io::Result<()> {
cvt(syscall::fsync(self.0.raw()))?;
Ok(())
}
pub fn datasync(&self) -> io::Result<()> {
self.fsync()
}
pub fn truncate(&self, size: u64) -> io::Result<()> {
cvt(syscall::ftruncate(self.0.raw(), size as usize))?;
Ok(())
}
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> {
crate::io::default_read_vectored(|buf| self.read(buf), bufs)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
crate::io::default_write_vectored(|buf| self.write(buf), bufs)
}
pub fn flush(&self) -> io::Result<()> { Ok(()) }
pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
let (whence, pos) = match pos {
// Casting to `i64` is fine, too large values will end up as
// negative which will cause an error in `lseek64`.
SeekFrom::Start(off) => (syscall::SEEK_SET, off as i64),
SeekFrom::End(off) => (syscall::SEEK_END, off),
SeekFrom::Current(off) => (syscall::SEEK_CUR, off),
};
let n = cvt(syscall::lseek(self.0.raw(), pos as isize, whence))?;
Ok(n as u64)
}
pub fn duplicate(&self) -> io::Result<File> {
self.0.duplicate().map(File)
}
pub fn dup(&self, buf: &[u8]) -> io::Result<File> {
let fd = cvt(syscall::dup(*self.fd().as_inner() as usize, buf))?;
Ok(File(FileDesc::new(fd)))
}
pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
set_perm(&self.path()?, perm)
}
pub fn path(&self) -> io::Result<PathBuf> {
let mut buf: [u8; 4096] = [0; 4096];
let count = cvt(syscall::fpath(*self.fd().as_inner() as usize, &mut buf))?;
Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }))
}
pub fn fd(&self) -> &FileDesc { &self.0 }
pub fn into_fd(self) -> FileDesc { self.0 }
}
impl DirBuilder {
pub fn new() -> DirBuilder {
DirBuilder { mode: 0o777 }
}
pub fn mkdir(&self, p: &Path) -> io::Result<()> {
let flags = syscall::O_CREAT | syscall::O_CLOEXEC | syscall::O_DIRECTORY | syscall::O_EXCL;
let fd = cvt(syscall::open(p.to_str().unwrap(), flags | (self.mode as usize & 0o777)))?;
let _ = syscall::close(fd);
Ok(())
}
pub fn set_mode(&mut self, mode: u32) {
self.mode = mode as u16;
}
}
impl FromInner<usize> for File {
fn from_inner(fd: usize) -> File {
File(FileDesc::new(fd))
}
}
impl fmt::Debug for File {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut b = f.debug_struct("File");
b.field("fd", &self.0.raw());
if let Ok(path) = self.path() {
b.field("path", &path);
}
/*
if let Some((read, write)) = get_mode(fd) {
b.field("read", &read).field("write", &write);
}
*/
b.finish()
}
}
pub fn readdir(p: &Path) -> io::Result<ReadDir> {
let root = Arc::new(p.to_path_buf());
let flags = syscall::O_CLOEXEC | syscall::O_RDONLY | syscall::O_DIRECTORY;
let fd = cvt(syscall::open(p.to_str().unwrap(), flags))?;
let file = FileDesc::new(fd);
let mut data = Vec::new();
file.read_to_end(&mut data)?;
Ok(ReadDir { data: data, i: 0, root: root })
}
pub fn unlink(p: &Path) -> io::Result<()> {
cvt(syscall::unlink(p.to_str().unwrap()))?;
Ok(())
}
pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
let fd = cvt(syscall::open(old.to_str().unwrap(),
syscall::O_CLOEXEC | syscall::O_STAT | syscall::O_NOFOLLOW))?;
let res = cvt(syscall::frename(fd, new.to_str().unwrap()));
cvt(syscall::close(fd))?;
res?;
Ok(())
}
pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
cvt(syscall::chmod(p.to_str().unwrap(), perm.mode as usize))?;
Ok(())
}
pub fn rmdir(p: &Path) -> io::Result<()> {
cvt(syscall::rmdir(p.to_str().unwrap()))?;
Ok(())
}
pub fn readlink(p: &Path) -> io::Result<PathBuf> {
let fd = cvt(syscall::open(p.to_str().unwrap(),
syscall::O_CLOEXEC | syscall::O_SYMLINK | syscall::O_RDONLY))?;
let mut buf: [u8; 4096] = [0; 4096];
let res = cvt(syscall::read(fd, &mut buf));
cvt(syscall::close(fd))?;
let count = res?;
Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }))
}
pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
let fd = cvt(syscall::open(dst.to_str().unwrap(),
syscall::O_CLOEXEC | syscall::O_SYMLINK |
syscall::O_CREAT | syscall::O_WRONLY | 0o777))?;
let res = cvt(syscall::write(fd, src.to_str().unwrap().as_bytes()));
cvt(syscall::close(fd))?;
res?;
Ok(())
}
pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
Err(Error::from_raw_os_error(syscall::ENOSYS))
}
pub fn stat(p: &Path) -> io::Result<FileAttr> {
let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_STAT))?;
let file = File(FileDesc::new(fd));
file.file_attr()
}
pub fn lstat(p: &Path) -> io::Result<FileAttr> {
let fd = cvt(syscall::open(p.to_str().unwrap(),
syscall::O_CLOEXEC | syscall::O_STAT | syscall::O_NOFOLLOW))?;
let file = File(FileDesc::new(fd));
file.file_attr()
}
pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_STAT))?;
let file = File(FileDesc::new(fd));
file.path()
}

View File

@ -1,46 +0,0 @@
use crate::mem;
pub struct IoSlice<'a>(&'a [u8]);
impl<'a> IoSlice<'a> {
#[inline]
pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
IoSlice(buf)
}
#[inline]
pub fn advance(&mut self, n: usize) {
self.0 = &self.0[n..]
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
self.0
}
}
pub struct IoSliceMut<'a>(&'a mut [u8]);
impl<'a> IoSliceMut<'a> {
#[inline]
pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
IoSliceMut(buf)
}
#[inline]
pub fn advance(&mut self, n: usize) {
let slice = mem::replace(&mut self.0, &mut []);
let (_, remaining) = slice.split_at_mut(n);
self.0 = remaining;
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
self.0
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
self.0
}
}

View File

@ -1,4 +0,0 @@
// Original implementation taken from rust-memchr.
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
pub use core::slice::memchr::{memchr, memrchr};

View File

@ -1,96 +0,0 @@
#![allow(dead_code, missing_docs, nonstandard_style)]
use crate::io::ErrorKind;
pub use libc::strlen;
pub use self::rand::hashmap_random_keys;
#[path = "../unix/alloc.rs"]
pub mod alloc;
pub mod args;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod ext;
pub mod fast_thread_local;
pub mod fd;
pub mod fs;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
pub mod rwlock;
pub mod stack_overflow;
pub mod stdio;
pub mod syscall;
pub mod thread;
pub mod thread_local;
pub mod time;
pub use crate::sys_common::os_str_bytes as os_str;
#[cfg(not(test))]
pub fn init() {}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno {
syscall::ECONNREFUSED => ErrorKind::ConnectionRefused,
syscall::ECONNRESET => ErrorKind::ConnectionReset,
syscall::EPERM | syscall::EACCES => ErrorKind::PermissionDenied,
syscall::EPIPE => ErrorKind::BrokenPipe,
syscall::ENOTCONN => ErrorKind::NotConnected,
syscall::ECONNABORTED => ErrorKind::ConnectionAborted,
syscall::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
syscall::EADDRINUSE => ErrorKind::AddrInUse,
syscall::ENOENT => ErrorKind::NotFound,
syscall::EINTR => ErrorKind::Interrupted,
syscall::EINVAL => ErrorKind::InvalidInput,
syscall::ETIMEDOUT => ErrorKind::TimedOut,
syscall::EEXIST => ErrorKind::AlreadyExists,
// These two constants can have the same value on some systems,
// but different values on others, so we can't use a match
// clause
x if x == syscall::EAGAIN || x == syscall::EWOULDBLOCK =>
ErrorKind::WouldBlock,
_ => ErrorKind::Other,
}
}
pub fn cvt(result: Result<usize, syscall::Error>) -> crate::io::Result<usize> {
result.map_err(|err| crate::io::Error::from_raw_os_error(err.errno))
}
#[doc(hidden)]
pub trait IsMinusOne {
fn is_minus_one(&self) -> bool;
}
macro_rules! impl_is_minus_one {
($($t:ident)*) => ($(impl IsMinusOne for $t {
fn is_minus_one(&self) -> bool {
*self == -1
}
})*)
}
impl_is_minus_one! { i8 i16 i32 i64 isize }
pub fn cvt_libc<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
if t.is_minus_one() {
Err(crate::io::Error::last_os_error())
} else {
Ok(t)
}
}
/// On Redox, use an illegal instruction to abort
pub unsafe fn abort_internal() -> ! {
core::intrinsics::abort();
}

View File

@ -1,169 +0,0 @@
use crate::cell::UnsafeCell;
use crate::intrinsics::{atomic_cxchg, atomic_xchg};
use crate::ptr;
use crate::sys::syscall::{futex, getpid, FUTEX_WAIT, FUTEX_WAKE};
pub unsafe fn mutex_try_lock(m: *mut i32) -> bool {
atomic_cxchg(m, 0, 1).0 == 0
}
pub unsafe fn mutex_lock(m: *mut i32) {
let mut c = 0;
//Set to larger value for longer spin test
for _i in 0..100 {
c = atomic_cxchg(m, 0, 1).0;
if c == 0 {
break;
}
//cpu_relax()
}
if c == 1 {
c = atomic_xchg(m, 2);
}
while c != 0 {
let _ = futex(m, FUTEX_WAIT, 2, 0, ptr::null_mut());
c = atomic_xchg(m, 2);
}
}
pub unsafe fn mutex_unlock(m: *mut i32) {
if *m == 2 {
*m = 0;
} else if atomic_xchg(m, 0) == 1 {
return;
}
//Set to larger value for longer spin test
for _i in 0..100 {
if *m != 0 {
if atomic_cxchg(m, 1, 2).0 != 0 {
return;
}
}
//cpu_relax()
}
let _ = futex(m, FUTEX_WAKE, 1, 0, ptr::null_mut());
}
pub struct Mutex {
pub lock: UnsafeCell<i32>,
}
impl Mutex {
/// Creates a new mutex.
pub const fn new() -> Self {
Mutex {
lock: UnsafeCell::new(0),
}
}
#[inline]
pub unsafe fn init(&self) {
*self.lock.get() = 0;
}
/// Try to lock the mutex
#[inline]
pub unsafe fn try_lock(&self) -> bool {
mutex_try_lock(self.lock.get())
}
/// Lock the mutex
#[inline]
pub unsafe fn lock(&self) {
mutex_lock(self.lock.get());
}
/// Unlock the mutex
#[inline]
pub unsafe fn unlock(&self) {
mutex_unlock(self.lock.get());
}
#[inline]
pub unsafe fn destroy(&self) {
*self.lock.get() = 0;
}
}
unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}
pub struct ReentrantMutex {
pub lock: UnsafeCell<i32>,
pub owner: UnsafeCell<usize>,
pub own_count: UnsafeCell<usize>,
}
impl ReentrantMutex {
pub const fn uninitialized() -> Self {
ReentrantMutex {
lock: UnsafeCell::new(0),
owner: UnsafeCell::new(0),
own_count: UnsafeCell::new(0),
}
}
#[inline]
pub unsafe fn init(&mut self) {
*self.lock.get() = 0;
*self.owner.get() = 0;
*self.own_count.get() = 0;
}
/// Try to lock the mutex
#[inline]
pub unsafe fn try_lock(&self) -> bool {
let pid = getpid().unwrap();
if *self.own_count.get() > 0 && *self.owner.get() == pid {
*self.own_count.get() += 1;
true
} else {
if mutex_try_lock(self.lock.get()) {
*self.owner.get() = pid;
*self.own_count.get() = 1;
true
} else {
false
}
}
}
/// Lock the mutex
#[inline]
pub unsafe fn lock(&self) {
let pid = getpid().unwrap();
if *self.own_count.get() > 0 && *self.owner.get() == pid {
*self.own_count.get() += 1;
} else {
mutex_lock(self.lock.get());
*self.owner.get() = pid;
*self.own_count.get() = 1;
}
}
/// Unlock the mutex
#[inline]
pub unsafe fn unlock(&self) {
let pid = getpid().unwrap();
if *self.own_count.get() > 0 && *self.owner.get() == pid {
*self.own_count.get() -= 1;
if *self.own_count.get() == 0 {
*self.owner.get() = 0;
mutex_unlock(self.lock.get());
}
}
}
#[inline]
pub unsafe fn destroy(&self) {
*self.lock.get() = 0;
*self.owner.get() = 0;
*self.own_count.get() = 0;
}
}
unsafe impl Send for ReentrantMutex {}
unsafe impl Sync for ReentrantMutex {}

View File

@ -1,12 +0,0 @@
use crate::string::String;
use crate::vec::Vec;
#[derive(Clone, Debug)]
pub struct DnsAnswer {
pub name: String,
pub a_type: u16,
pub a_class: u16,
pub ttl_a: u16,
pub ttl_b: u16,
pub data: Vec<u8>
}

View File

@ -1,205 +0,0 @@
pub use self::answer::DnsAnswer;
pub use self::query::DnsQuery;
use crate::slice;
use crate::u16;
use crate::string::String;
use crate::vec::Vec;
mod answer;
mod query;
#[unstable(feature = "n16", issue="0")]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Default)]
#[repr(packed)]
pub struct n16 {
inner: u16
}
impl n16 {
#[unstable(feature = "n16", issue="0")]
pub fn as_bytes(&self) -> &[u8] {
unsafe { slice::from_raw_parts((&self.inner as *const u16) as *const u8, 2) }
}
#[unstable(feature = "n16", issue="0")]
pub fn from_bytes(bytes: &[u8]) -> Self {
n16 {
inner: unsafe { slice::from_raw_parts(bytes.as_ptr() as *const u16, bytes.len()/2)[0] }
}
}
}
#[unstable(feature = "n16", issue="0")]
impl From<u16> for n16 {
fn from(value: u16) -> Self {
n16 {
inner: value.to_be()
}
}
}
#[unstable(feature = "n16", issue="0")]
impl From<n16> for u16 {
fn from(value: n16) -> Self {
u16::from_be(value.inner)
}
}
#[derive(Clone, Debug)]
pub struct Dns {
pub transaction_id: u16,
pub flags: u16,
pub queries: Vec<DnsQuery>,
pub answers: Vec<DnsAnswer>
}
impl Dns {
pub fn compile(&self) -> Vec<u8> {
let mut data = Vec::new();
macro_rules! push_u8 {
($value:expr) => {
data.push($value);
};
};
macro_rules! push_n16 {
($value:expr) => {
data.extend_from_slice(n16::from($value).as_bytes());
};
};
push_n16!(self.transaction_id);
push_n16!(self.flags);
push_n16!(self.queries.len() as u16);
push_n16!(self.answers.len() as u16);
push_n16!(0);
push_n16!(0);
for query in self.queries.iter() {
for part in query.name.split('.') {
push_u8!(part.len() as u8);
data.extend_from_slice(part.as_bytes());
}
push_u8!(0);
push_n16!(query.q_type);
push_n16!(query.q_class);
}
data
}
pub fn parse(data: &[u8]) -> Result<Self, String> {
let name_ind = 0b11000000;
let mut i = 0;
macro_rules! pop_u8 {
() => {
{
i += 1;
if i > data.len() {
return Err(format!("{}: {}: pop_u8", file!(), line!()));
}
data[i - 1]
}
};
};
macro_rules! pop_n16 {
() => {
{
i += 2;
if i > data.len() {
return Err(format!("{}: {}: pop_n16", file!(), line!()));
}
u16::from(n16::from_bytes(&data[i - 2 .. i]))
}
};
};
macro_rules! pop_data {
() => {
{
let mut data = Vec::new();
let data_len = pop_n16!();
for _data_i in 0..data_len {
data.push(pop_u8!());
}
data
}
};
};
macro_rules! pop_name {
() => {
{
let mut name = String::new();
let old_i = i;
loop {
let name_len = pop_u8!();
if name_len & name_ind == name_ind {
i -= 1;
i = (pop_n16!() - ((name_ind as u16) << 8)) as usize;
continue;
}
if name_len == 0 {
break;
}
if ! name.is_empty() {
name.push('.');
}
for _name_i in 0..name_len {
name.push(pop_u8!() as char);
}
}
if i <= old_i {
i = old_i + 2;
}
name
}
};
};
let transaction_id = pop_n16!();
let flags = pop_n16!();
let queries_len = pop_n16!();
let answers_len = pop_n16!();
pop_n16!();
pop_n16!();
let mut queries = Vec::new();
for _query_i in 0..queries_len {
queries.push(DnsQuery {
name: pop_name!(),
q_type: pop_n16!(),
q_class: pop_n16!()
});
}
let mut answers = Vec::new();
for _answer_i in 0..answers_len {
answers.push(DnsAnswer {
name: pop_name!(),
a_type: pop_n16!(),
a_class: pop_n16!(),
ttl_a: pop_n16!(),
ttl_b: pop_n16!(),
data: pop_data!()
});
}
Ok(Dns {
transaction_id,
flags,
queries,
answers,
})
}
}

View File

@ -1,8 +0,0 @@
use crate::string::String;
#[derive(Clone, Debug)]
pub struct DnsQuery {
pub name: String,
pub q_type: u16,
pub q_class: u16
}

View File

@ -1,140 +0,0 @@
use crate::fs::File;
use crate::io::{Error, Read, self};
use crate::iter::Iterator;
use crate::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use crate::str::FromStr;
use crate::string::{String, ToString};
use crate::sys::syscall::EINVAL;
use crate::time::{self, Duration};
use crate::vec::{IntoIter, Vec};
use crate::convert::{TryFrom, TryInto};
use self::dns::{Dns, DnsQuery};
pub use self::tcp::{TcpStream, TcpListener};
pub use self::udp::UdpSocket;
pub mod netc;
mod dns;
mod tcp;
mod udp;
pub struct LookupHost(IntoIter<SocketAddr>, u16);
impl LookupHost {
pub fn port(&self) -> u16 {
self.1
}
}
impl Iterator for LookupHost {
type Item = SocketAddr;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl TryFrom<&str> for LookupHost {
type Error = io::Error;
fn try_from(s: &str) -> io::Result<LookupHost> {
macro_rules! try_opt {
($e:expr, $msg:expr) => (
match $e {
Some(r) => r,
None => return Err(io::Error::new(io::ErrorKind::InvalidInput,
$msg)),
}
)
}
// split the string by ':' and convert the second part to u16
let mut parts_iter = s.rsplitn(2, ':');
let port_str = try_opt!(parts_iter.next(), "invalid socket address");
let host = try_opt!(parts_iter.next(), "invalid socket address");
let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
(host, port).try_into()
}
}
impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
type Error = io::Error;
fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
let mut ip_string = String::new();
File::open("/etc/net/ip")?.read_to_string(&mut ip_string)?;
let ip: Vec<u8> = ip_string.trim().split('.').map(|part| part.parse::<u8>()
.unwrap_or(0)).collect();
let mut dns_string = String::new();
File::open("/etc/net/dns")?.read_to_string(&mut dns_string)?;
let dns: Vec<u8> = dns_string.trim().split('.').map(|part| part.parse::<u8>()
.unwrap_or(0)).collect();
if ip.len() == 4 && dns.len() == 4 {
let time = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap();
let tid = (time.subsec_nanos() >> 16) as u16;
let packet = Dns {
transaction_id: tid,
flags: 0x0100,
queries: vec![DnsQuery {
name: host.to_string(),
q_type: 0x0001,
q_class: 0x0001,
}],
answers: vec![]
};
let packet_data = packet.compile();
let my_ip = Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]);
let dns_ip = Ipv4Addr::new(dns[0], dns[1], dns[2], dns[3]);
let socket = UdpSocket::bind(Ok(&SocketAddr::V4(SocketAddrV4::new(my_ip, 0))))?;
socket.set_read_timeout(Some(Duration::new(5, 0)))?;
socket.set_write_timeout(Some(Duration::new(5, 0)))?;
socket.connect(Ok(&SocketAddr::V4(SocketAddrV4::new(dns_ip, 53))))?;
socket.send(&packet_data)?;
let mut buf = [0; 65536];
let count = socket.recv(&mut buf)?;
match Dns::parse(&buf[.. count]) {
Ok(response) => {
let mut addrs = vec![];
for answer in response.answers.iter() {
if answer.a_type == 0x0001 && answer.a_class == 0x0001
&& answer.data.len() == 4
{
let answer_ip = Ipv4Addr::new(answer.data[0],
answer.data[1],
answer.data[2],
answer.data[3]);
addrs.push(SocketAddr::V4(SocketAddrV4::new(answer_ip, 0)));
}
}
Ok(LookupHost(addrs.into_iter(), port))
},
Err(_err) => Err(Error::from_raw_os_error(EINVAL))
}
} else {
Err(Error::from_raw_os_error(EINVAL))
}
}
}
fn path_to_peer_addr(path_str: &str) -> SocketAddr {
let mut parts = path_str.split('/').next().unwrap_or("").split(':').skip(1);
let host = Ipv4Addr::from_str(parts.next().unwrap_or("")).unwrap_or(Ipv4Addr::new(0, 0, 0, 0));
let port = parts.next().unwrap_or("").parse::<u16>().unwrap_or(0);
SocketAddr::V4(SocketAddrV4::new(host, port))
}
fn path_to_local_addr(path_str: &str) -> SocketAddr {
let mut parts = path_str.split('/').nth(1).unwrap_or("").split(':');
let host = Ipv4Addr::from_str(parts.next().unwrap_or("")).unwrap_or(Ipv4Addr::new(0, 0, 0, 0));
let port = parts.next().unwrap_or("").parse::<u16>().unwrap_or(0);
SocketAddr::V4(SocketAddrV4::new(host, port))
}

View File

@ -1,47 +0,0 @@
pub type in_addr_t = u32;
pub type in_port_t = u16;
pub type socklen_t = u32;
pub type sa_family_t = u16;
pub const AF_INET: sa_family_t = 2;
pub const AF_INET6: sa_family_t = 23;
#[derive(Copy, Clone)]
#[repr(C)]
pub struct in_addr {
pub s_addr: in_addr_t,
}
#[derive(Copy, Clone)]
#[repr(align(4))]
#[repr(C)]
pub struct in6_addr {
pub s6_addr: [u8; 16],
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct sockaddr {
pub sa_family: sa_family_t,
pub sa_data: [u8; 14],
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct sockaddr_in {
pub sin_family: sa_family_t,
pub sin_port: in_port_t,
pub sin_addr: in_addr,
pub sin_zero: [u8; 8],
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct sockaddr_in6 {
pub sin6_family: sa_family_t,
pub sin6_port: in_port_t,
pub sin6_flowinfo: u32,
pub sin6_addr: in6_addr,
pub sin6_scope_id: u32,
}

View File

@ -1,251 +0,0 @@
use crate::cmp;
use crate::io::{self, Error, ErrorKind, Result, IoSlice, IoSliceMut};
use crate::mem;
use crate::net::{SocketAddr, Shutdown};
use crate::path::Path;
use crate::sys::fs::{File, OpenOptions};
use crate::sys::syscall::TimeSpec;
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::time::Duration;
use super::{path_to_peer_addr, path_to_local_addr};
#[derive(Debug)]
pub struct TcpStream(File);
impl TcpStream {
pub fn connect(addr: Result<&SocketAddr>) -> Result<TcpStream> {
let path = format!("tcp:{}", addr?);
let mut options = OpenOptions::new();
options.read(true);
options.write(true);
Ok(TcpStream(File::open(Path::new(path.as_str()), &options)?))
}
pub fn connect_timeout(_addr: &SocketAddr, _timeout: Duration) -> Result<TcpStream> {
Err(Error::new(ErrorKind::Other, "TcpStream::connect_timeout not implemented"))
}
pub fn duplicate(&self) -> Result<TcpStream> {
Ok(TcpStream(self.0.dup(&[])?))
}
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
self.0.read(buf)
}
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
io::default_read_vectored(|b| self.read(b), bufs)
}
pub fn write(&self, buf: &[u8]) -> Result<usize> {
self.0.write(buf)
}
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
io::default_write_vectored(|b| self.write(b), bufs)
}
pub fn take_error(&self) -> Result<Option<Error>> {
Ok(None)
}
pub fn peer_addr(&self) -> Result<SocketAddr> {
let path = self.0.path()?;
Ok(path_to_peer_addr(path.to_str().unwrap_or("")))
}
pub fn socket_addr(&self) -> Result<SocketAddr> {
let path = self.0.path()?;
Ok(path_to_local_addr(path.to_str().unwrap_or("")))
}
pub fn peek(&self, _buf: &mut [u8]) -> Result<usize> {
Err(Error::new(ErrorKind::Other, "TcpStream::peek not implemented"))
}
pub fn shutdown(&self, _how: Shutdown) -> Result<()> {
Err(Error::new(ErrorKind::Other, "TcpStream::shutdown not implemented"))
}
pub fn nodelay(&self) -> Result<bool> {
Err(Error::new(ErrorKind::Other, "TcpStream::nodelay not implemented"))
}
pub fn nonblocking(&self) -> Result<bool> {
self.0.fd().nonblocking()
}
pub fn only_v6(&self) -> Result<bool> {
Err(Error::new(ErrorKind::Other, "TcpStream::only_v6 not implemented"))
}
pub fn ttl(&self) -> Result<u32> {
let mut ttl = [0];
let file = self.0.dup(b"ttl")?;
file.read(&mut ttl)?;
Ok(ttl[0] as u32)
}
pub fn read_timeout(&self) -> Result<Option<Duration>> {
let mut time = TimeSpec::default();
let file = self.0.dup(b"read_timeout")?;
if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
} else {
Ok(None)
}
}
pub fn write_timeout(&self) -> Result<Option<Duration>> {
let mut time = TimeSpec::default();
let file = self.0.dup(b"write_timeout")?;
if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
} else {
Ok(None)
}
}
pub fn set_nodelay(&self, _nodelay: bool) -> Result<()> {
Err(Error::new(ErrorKind::Other, "TcpStream::set_nodelay not implemented"))
}
pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> {
self.0.fd().set_nonblocking(nonblocking)
}
pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
Err(Error::new(ErrorKind::Other, "TcpStream::set_only_v6 not implemented"))
}
pub fn set_ttl(&self, ttl: u32) -> Result<()> {
let file = self.0.dup(b"ttl")?;
file.write(&[cmp::min(ttl, 255) as u8])?;
Ok(())
}
pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
let file = self.0.dup(b"read_timeout")?;
if let Some(duration) = duration_option {
if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
return Err(io::Error::new(io::ErrorKind::InvalidInput,
"cannot set a 0 duration timeout"));
}
file.write(&TimeSpec {
tv_sec: duration.as_secs() as i64,
tv_nsec: duration.subsec_nanos() as i32
})?;
} else {
file.write(&[])?;
}
Ok(())
}
pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
let file = self.0.dup(b"write_timeout")?;
if let Some(duration) = duration_option {
if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
return Err(io::Error::new(io::ErrorKind::InvalidInput,
"cannot set a 0 duration timeout"));
}
file.write(&TimeSpec {
tv_sec: duration.as_secs() as i64,
tv_nsec: duration.subsec_nanos() as i32
})?;
} else {
file.write(&[])?;
}
Ok(())
}
}
impl AsInner<File> for TcpStream {
fn as_inner(&self) -> &File { &self.0 }
}
impl FromInner<File> for TcpStream {
fn from_inner(file: File) -> TcpStream {
TcpStream(file)
}
}
impl IntoInner<File> for TcpStream {
fn into_inner(self) -> File { self.0 }
}
#[derive(Debug)]
pub struct TcpListener(File);
impl TcpListener {
pub fn bind(addr: Result<&SocketAddr>) -> Result<TcpListener> {
let path = format!("tcp:/{}", addr?);
let mut options = OpenOptions::new();
options.read(true);
options.write(true);
Ok(TcpListener(File::open(Path::new(path.as_str()), &options)?))
}
pub fn accept(&self) -> Result<(TcpStream, SocketAddr)> {
let file = self.0.dup(b"listen")?;
let path = file.path()?;
let peer_addr = path_to_peer_addr(path.to_str().unwrap_or(""));
Ok((TcpStream(file), peer_addr))
}
pub fn duplicate(&self) -> Result<TcpListener> {
Ok(TcpListener(self.0.dup(&[])?))
}
pub fn take_error(&self) -> Result<Option<Error>> {
Ok(None)
}
pub fn socket_addr(&self) -> Result<SocketAddr> {
let path = self.0.path()?;
Ok(path_to_local_addr(path.to_str().unwrap_or("")))
}
pub fn nonblocking(&self) -> Result<bool> {
Err(Error::new(ErrorKind::Other, "TcpListener::nonblocking not implemented"))
}
pub fn only_v6(&self) -> Result<bool> {
Err(Error::new(ErrorKind::Other, "TcpListener::only_v6 not implemented"))
}
pub fn ttl(&self) -> Result<u32> {
let mut ttl = [0];
let file = self.0.dup(b"ttl")?;
file.read(&mut ttl)?;
Ok(ttl[0] as u32)
}
pub fn set_nonblocking(&self, _nonblocking: bool) -> Result<()> {
Err(Error::new(ErrorKind::Other, "TcpListener::set_nonblocking not implemented"))
}
pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
Err(Error::new(ErrorKind::Other, "TcpListener::set_only_v6 not implemented"))
}
pub fn set_ttl(&self, ttl: u32) -> Result<()> {
let file = self.0.dup(b"ttl")?;
file.write(&[cmp::min(ttl, 255) as u8])?;
Ok(())
}
}
impl AsInner<File> for TcpListener {
fn as_inner(&self) -> &File { &self.0 }
}
impl FromInner<File> for TcpListener {
fn from_inner(file: File) -> TcpListener {
TcpListener(file)
}
}
impl IntoInner<File> for TcpListener {
fn into_inner(self) -> File { self.0 }
}

View File

@ -1,237 +0,0 @@
use crate::cell::UnsafeCell;
use crate::cmp;
use crate::io::{self, Error, ErrorKind, Result};
use crate::mem;
use crate::net::{SocketAddr, Ipv4Addr, Ipv6Addr};
use crate::path::Path;
use crate::sys::fs::{File, OpenOptions};
use crate::sys::syscall::TimeSpec;
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::time::Duration;
use super::{path_to_peer_addr, path_to_local_addr};
#[derive(Debug)]
pub struct UdpSocket(File, UnsafeCell<Option<SocketAddr>>);
impl UdpSocket {
pub fn bind(addr: Result<&SocketAddr>) -> Result<UdpSocket> {
let path = format!("udp:/{}", addr?);
let mut options = OpenOptions::new();
options.read(true);
options.write(true);
Ok(UdpSocket(File::open(Path::new(path.as_str()), &options)?, UnsafeCell::new(None)))
}
fn get_conn(&self) -> &mut Option<SocketAddr> {
unsafe { &mut *(self.1.get()) }
}
pub fn connect(&self, addr: Result<&SocketAddr>) -> Result<()> {
unsafe { *self.1.get() = Some(*addr?) };
Ok(())
}
pub fn duplicate(&self) -> Result<UdpSocket> {
let new_bind = self.0.dup(&[])?;
let new_conn = *self.get_conn();
Ok(UdpSocket(new_bind, UnsafeCell::new(new_conn)))
}
pub fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
let from = self.0.dup(b"listen")?;
let path = from.path()?;
let peer_addr = path_to_peer_addr(path.to_str().unwrap_or(""));
let count = from.read(buf)?;
Ok((count, peer_addr))
}
pub fn recv(&self, buf: &mut [u8]) -> Result<usize> {
if let Some(addr) = *self.get_conn() {
let from = self.0.dup(addr.to_string().as_bytes())?;
from.read(buf)
} else {
Err(Error::new(ErrorKind::Other, "UdpSocket::recv not connected"))
}
}
pub fn send_to(&self, buf: &[u8], addr: &SocketAddr) -> Result<usize> {
let to = self.0.dup(format!("{}", addr).as_bytes())?;
to.write(buf)
}
pub fn send(&self, buf: &[u8]) -> Result<usize> {
if let Some(addr) = *self.get_conn() {
self.send_to(buf, &addr)
} else {
Err(Error::new(ErrorKind::Other, "UdpSocket::send not connected"))
}
}
pub fn take_error(&self) -> Result<Option<Error>> {
Ok(None)
}
pub fn peer_addr(&self) -> Result<SocketAddr> {
let path = self.0.path()?;
Ok(path_to_peer_addr(path.to_str().unwrap_or("")))
}
pub fn socket_addr(&self) -> Result<SocketAddr> {
let path = self.0.path()?;
Ok(path_to_local_addr(path.to_str().unwrap_or("")))
}
pub fn peek(&self, _buf: &mut [u8]) -> Result<usize> {
Err(Error::new(ErrorKind::Other, "UdpSocket::peek not implemented"))
}
pub fn peek_from(&self, _buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
Err(Error::new(ErrorKind::Other, "UdpSocket::peek_from not implemented"))
}
pub fn broadcast(&self) -> Result<bool> {
Err(Error::new(ErrorKind::Other, "UdpSocket::broadcast not implemented"))
}
pub fn multicast_loop_v4(&self) -> Result<bool> {
Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_loop_v4 not implemented"))
}
pub fn multicast_loop_v6(&self) -> Result<bool> {
Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_loop_v6 not implemented"))
}
pub fn multicast_ttl_v4(&self) -> Result<u32> {
Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_ttl_v4 not implemented"))
}
pub fn nonblocking(&self) -> Result<bool> {
self.0.fd().nonblocking()
}
pub fn only_v6(&self) -> Result<bool> {
Err(Error::new(ErrorKind::Other, "UdpSocket::only_v6 not implemented"))
}
pub fn ttl(&self) -> Result<u32> {
let mut ttl = [0];
let file = self.0.dup(b"ttl")?;
file.read(&mut ttl)?;
Ok(ttl[0] as u32)
}
pub fn read_timeout(&self) -> Result<Option<Duration>> {
let mut time = TimeSpec::default();
let file = self.0.dup(b"read_timeout")?;
if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
} else {
Ok(None)
}
}
pub fn write_timeout(&self) -> Result<Option<Duration>> {
let mut time = TimeSpec::default();
let file = self.0.dup(b"write_timeout")?;
if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
} else {
Ok(None)
}
}
pub fn set_broadcast(&self, _broadcast: bool) -> Result<()> {
Err(Error::new(ErrorKind::Other, "UdpSocket::set_broadcast not implemented"))
}
pub fn set_multicast_loop_v4(&self, _multicast_loop_v4: bool) -> Result<()> {
Err(Error::new(ErrorKind::Other, "UdpSocket::set_multicast_loop_v4 not implemented"))
}
pub fn set_multicast_loop_v6(&self, _multicast_loop_v6: bool) -> Result<()> {
Err(Error::new(ErrorKind::Other, "UdpSocket::set_multicast_loop_v6 not implemented"))
}
pub fn set_multicast_ttl_v4(&self, _multicast_ttl_v4: u32) -> Result<()> {
Err(Error::new(ErrorKind::Other, "UdpSocket::set_multicast_ttl_v4 not implemented"))
}
pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> {
self.0.fd().set_nonblocking(nonblocking)
}
pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
Err(Error::new(ErrorKind::Other, "UdpSocket::set_only_v6 not implemented"))
}
pub fn set_ttl(&self, ttl: u32) -> Result<()> {
let file = self.0.dup(b"ttl")?;
file.write(&[cmp::min(ttl, 255) as u8])?;
Ok(())
}
pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
let file = self.0.dup(b"read_timeout")?;
if let Some(duration) = duration_option {
if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
return Err(io::Error::new(io::ErrorKind::InvalidInput,
"cannot set a 0 duration timeout"));
}
file.write(&TimeSpec {
tv_sec: duration.as_secs() as i64,
tv_nsec: duration.subsec_nanos() as i32
})?;
} else {
file.write(&[])?;
}
Ok(())
}
pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
let file = self.0.dup(b"write_timeout")?;
if let Some(duration) = duration_option {
if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
return Err(io::Error::new(io::ErrorKind::InvalidInput,
"cannot set a 0 duration timeout"));
}
file.write(&TimeSpec {
tv_sec: duration.as_secs() as i64,
tv_nsec: duration.subsec_nanos() as i32
})?;
} else {
file.write(&[])?;
}
Ok(())
}
pub fn join_multicast_v4(&self, _multiaddr: &Ipv4Addr, _interface: &Ipv4Addr) -> Result<()> {
Err(Error::new(ErrorKind::Other, "UdpSocket::join_multicast_v4 not implemented"))
}
pub fn join_multicast_v6(&self, _multiaddr: &Ipv6Addr, _interface: u32) -> Result<()> {
Err(Error::new(ErrorKind::Other, "UdpSocket::join_multicast_v6 not implemented"))
}
pub fn leave_multicast_v4(&self, _multiaddr: &Ipv4Addr, _interface: &Ipv4Addr) -> Result<()> {
Err(Error::new(ErrorKind::Other, "UdpSocket::leave_multicast_v4 not implemented"))
}
pub fn leave_multicast_v6(&self, _multiaddr: &Ipv6Addr, _interface: u32) -> Result<()> {
Err(Error::new(ErrorKind::Other, "UdpSocket::leave_multicast_v6 not implemented"))
}
}
impl AsInner<File> for UdpSocket {
fn as_inner(&self) -> &File { &self.0 }
}
impl FromInner<File> for UdpSocket {
fn from_inner(file: File) -> UdpSocket {
UdpSocket(file, UnsafeCell::new(None))
}
}
impl IntoInner<File> for UdpSocket {
fn into_inner(self) -> File { self.0 }
}

View File

@ -1,241 +0,0 @@
//! Implementation of `std::os` functionality for unix systems
#![allow(unused_imports)] // lots of cfg code here
use libc::c_char;
use crate::os::unix::prelude::*;
use crate::error::Error as StdError;
use crate::ffi::{CStr, CString, OsStr, OsString};
use crate::fmt;
use crate::io::{self, Read, Write};
use crate::iter;
use crate::marker::PhantomData;
use crate::mem;
use crate::memchr;
use crate::path::{self, PathBuf};
use crate::ptr;
use crate::slice;
use crate::str;
use crate::sys_common::mutex::Mutex;
use crate::sys::{cvt, cvt_libc, fd, syscall};
use crate::vec;
extern {
#[link_name = "__errno_location"]
fn errno_location() -> *mut i32;
}
/// Returns the platform-specific value of errno
pub fn errno() -> i32 {
unsafe {
(*errno_location())
}
}
/// Gets a detailed string description for the given error number.
pub fn error_string(errno: i32) -> String {
if let Some(string) = syscall::STR_ERROR.get(errno as usize) {
string.to_string()
} else {
"unknown error".to_string()
}
}
pub fn getcwd() -> io::Result<PathBuf> {
let mut buf = [0; 4096];
let count = cvt(syscall::getcwd(&mut buf))?;
Ok(PathBuf::from(OsString::from_vec(buf[.. count].to_vec())))
}
pub fn chdir(p: &path::Path) -> io::Result<()> {
cvt(syscall::chdir(p.to_str().unwrap())).and(Ok(()))
}
pub struct SplitPaths<'a> {
iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
fn(&'a [u8]) -> PathBuf>,
}
pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
fn bytes_to_path(b: &[u8]) -> PathBuf {
PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
}
fn is_semicolon(b: &u8) -> bool { *b == b';' }
let unparsed = unparsed.as_bytes();
SplitPaths {
iter: unparsed.split(is_semicolon as fn(&u8) -> bool)
.map(bytes_to_path as fn(&[u8]) -> PathBuf)
}
}
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() }
}
#[derive(Debug)]
pub struct JoinPathsError;
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
where I: Iterator<Item=T>, T: AsRef<OsStr>
{
let mut joined = Vec::new();
let sep = b';';
for (i, path) in paths.enumerate() {
let path = path.as_ref().as_bytes();
if i > 0 { joined.push(sep) }
if path.contains(&sep) {
return Err(JoinPathsError)
}
joined.extend_from_slice(path);
}
Ok(OsStringExt::from_vec(joined))
}
impl fmt::Display for JoinPathsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
"path segment contains separator `:`".fmt(f)
}
}
impl StdError for JoinPathsError {
fn description(&self) -> &str { "failed to join paths" }
}
pub fn current_exe() -> io::Result<PathBuf> {
use crate::fs::File;
let mut file = File::open("sys:exe")?;
let mut path = String::new();
file.read_to_string(&mut path)?;
if path.ends_with('\n') {
path.pop();
}
Ok(PathBuf::from(path))
}
pub static ENV_LOCK: Mutex = Mutex::new();
pub struct Env {
iter: vec::IntoIter<(OsString, OsString)>,
_dont_send_or_sync_me: PhantomData<*mut ()>,
}
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() }
}
pub unsafe fn environ() -> *mut *const *const c_char {
extern { static mut environ: *const *const c_char; }
&mut environ
}
/// Returns a vector of (variable, value) byte-vector pairs for all the
/// environment variables of the current process.
pub fn env() -> Env {
unsafe {
let _guard = ENV_LOCK.lock();
let mut environ = *environ();
if environ == ptr::null() {
panic!("os::env() failure getting env string from OS: {}",
io::Error::last_os_error());
}
let mut result = Vec::new();
while *environ != ptr::null() {
if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
result.push(key_value);
}
environ = environ.offset(1);
}
return Env {
iter: result.into_iter(),
_dont_send_or_sync_me: PhantomData,
}
}
fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
// Strategy (copied from glibc): Variable name and value are separated
// by an ASCII equals sign '='. Since a variable name must not be
// empty, allow variable names starting with an equals sign. Skip all
// malformed lines.
if input.is_empty() {
return None;
}
let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
pos.map(|p| (
OsStringExt::from_vec(input[..p].to_vec()),
OsStringExt::from_vec(input[p+1..].to_vec()),
))
}
}
pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
// environment variables with a nul byte can't be set, so their value is
// always None as well
let k = CString::new(k.as_bytes())?;
unsafe {
let _guard = ENV_LOCK.lock();
let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
let ret = if s.is_null() {
None
} else {
Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
};
Ok(ret)
}
}
pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
let k = CString::new(k.as_bytes())?;
let v = CString::new(v.as_bytes())?;
unsafe {
let _guard = ENV_LOCK.lock();
cvt_libc(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
}
}
pub fn unsetenv(n: &OsStr) -> io::Result<()> {
let nbuf = CString::new(n.as_bytes())?;
unsafe {
let _guard = ENV_LOCK.lock();
cvt_libc(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
}
}
pub fn page_size() -> usize {
4096
}
pub fn temp_dir() -> PathBuf {
crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
PathBuf::from("/tmp")
})
}
pub fn home_dir() -> Option<PathBuf> {
return crate::env::var_os("HOME").map(PathBuf::from);
}
pub fn exit(code: i32) -> ! {
let _ = syscall::exit(code as usize);
unreachable!();
}
pub fn getpid() -> u32 {
syscall::getpid().unwrap() as u32
}
pub fn getppid() -> u32 {
syscall::getppid().unwrap() as u32
}

View File

@ -1,29 +0,0 @@
use crate::ffi::OsStr;
use crate::path::Prefix;
#[inline]
pub fn is_sep_byte(b: u8) -> bool {
b == b'/'
}
#[inline]
pub fn is_verbatim_sep(b: u8) -> bool {
b == b'/'
}
pub fn parse_prefix(path: &OsStr) -> Option<Prefix<'_>> {
if let Some(path_str) = path.to_str() {
if let Some(_i) = path_str.find(':') {
// FIXME: Redox specific prefix
// Some(Prefix::Verbatim(OsStr::new(&path_str[..i])))
None
} else {
None
}
} else {
None
}
}
pub const MAIN_SEP_STR: &str = "/";
pub const MAIN_SEP: char = '/';

View File

@ -1,101 +0,0 @@
use crate::io::{self, IoSlice, IoSliceMut};
use crate::sys::{cvt, syscall};
use crate::sys::fd::FileDesc;
////////////////////////////////////////////////////////////////////////////////
// Anonymous pipes
////////////////////////////////////////////////////////////////////////////////
pub struct AnonPipe(FileDesc);
pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
let mut fds = [0; 2];
cvt(syscall::pipe2(&mut fds, syscall::O_CLOEXEC))?;
Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1]))))
}
impl AnonPipe {
pub fn from_fd(fd: FileDesc) -> io::Result<AnonPipe> {
fd.set_cloexec()?;
Ok(AnonPipe(fd))
}
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> {
crate::io::default_read_vectored(|buf| self.read(buf), bufs)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
crate::io::default_write_vectored(|buf| self.write(buf), bufs)
}
pub fn fd(&self) -> &FileDesc { &self.0 }
pub fn into_fd(self) -> FileDesc { self.0 }
}
pub fn read2(p1: AnonPipe,
v1: &mut Vec<u8>,
p2: AnonPipe,
v2: &mut Vec<u8>) -> io::Result<()> {
//FIXME: Use event based I/O multiplexing
//unimplemented!()
p1.0.read_to_end(v1)?;
p2.0.read_to_end(v2)?;
Ok(())
/*
// Set both pipes into nonblocking mode as we're gonna be reading from both
// in the `select` loop below, and we wouldn't want one to block the other!
let p1 = p1.into_fd();
let p2 = p2.into_fd();
p1.set_nonblocking(true)?;
p2.set_nonblocking(true)?;
loop {
// wait for either pipe to become readable using `select`
cvt_r(|| unsafe {
let mut read: libc::fd_set = mem::zeroed();
libc::FD_SET(p1.raw(), &mut read);
libc::FD_SET(p2.raw(), &mut read);
libc::select(max + 1, &mut read, ptr::null_mut(), ptr::null_mut(),
ptr::null_mut())
})?;
// Read as much as we can from each pipe, ignoring EWOULDBLOCK or
// EAGAIN. If we hit EOF, then this will happen because the underlying
// reader will return Ok(0), in which case we'll see `Ok` ourselves. In
// this case we flip the other fd back into blocking mode and read
// whatever's leftover on that file descriptor.
let read = |fd: &FileDesc, dst: &mut Vec<u8>| {
match fd.read_to_end(dst) {
Ok(_) => Ok(true),
Err(e) => {
if e.raw_os_error() == Some(libc::EWOULDBLOCK) ||
e.raw_os_error() == Some(libc::EAGAIN) {
Ok(false)
} else {
Err(e)
}
}
}
};
if read(&p1, v1)? {
p2.set_nonblocking(false)?;
return p2.read_to_end(v2).map(|_| ());
}
if read(&p2, v2)? {
p1.set_nonblocking(false)?;
return p1.read_to_end(v1).map(|_| ());
}
}
*/
}

View File

@ -1,609 +0,0 @@
use crate::env::{self, split_paths};
use crate::ffi::{CStr, OsStr};
use crate::fmt;
use crate::fs::File;
use crate::io::{self, prelude::*, BufReader, Error, ErrorKind, SeekFrom};
use crate::os::unix::ffi::OsStrExt;
use crate::path::{Path, PathBuf};
use crate::ptr;
use crate::sys::ext::fs::MetadataExt;
use crate::sys::ext::io::AsRawFd;
use crate::sys::fd::FileDesc;
use crate::sys::fs::{File as SysFile, OpenOptions};
use crate::sys::os::{ENV_LOCK, environ};
use crate::sys::pipe::{self, AnonPipe};
use crate::sys::{cvt, syscall};
use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
use libc::{EXIT_SUCCESS, EXIT_FAILURE};
////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////
pub struct Command {
// Currently we try hard to ensure that the call to `.exec()` doesn't
// actually allocate any memory. While many platforms try to ensure that
// memory allocation works after a fork in a multithreaded process, it's
// been observed to be buggy and somewhat unreliable, so we do our best to
// just not do it at all!
//
// Along those lines, the `argv` and `envp` raw pointers here are exactly
// what's gonna get passed to `execvp`. The `argv` array starts with the
// `program` and ends with a NULL, and the `envp` pointer, if present, is
// also null-terminated.
//
// Right now we don't support removing arguments, so there's no much fancy
// support there, but we support adding and removing environment variables,
// so a side table is used to track where in the `envp` array each key is
// located. Whenever we add a key we update it in place if it's already
// present, and whenever we remove a key we update the locations of all
// other keys.
program: String,
args: Vec<String>,
env: CommandEnv<DefaultEnvKey>,
cwd: Option<String>,
uid: Option<u32>,
gid: Option<u32>,
saw_nul: bool,
closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
stdin: Option<Stdio>,
stdout: Option<Stdio>,
stderr: Option<Stdio>,
}
// passed back to std::process with the pipes connected to the child, if any
// were requested
pub struct StdioPipes {
pub stdin: Option<AnonPipe>,
pub stdout: Option<AnonPipe>,
pub stderr: Option<AnonPipe>,
}
// passed to do_exec() with configuration of what the child stdio should look
// like
struct ChildPipes {
stdin: ChildStdio,
stdout: ChildStdio,
stderr: ChildStdio,
}
enum ChildStdio {
Inherit,
Explicit(usize),
Owned(FileDesc),
}
pub enum Stdio {
Inherit,
Null,
MakePipe,
Fd(FileDesc),
}
impl Command {
pub fn new(program: &OsStr) -> Command {
Command {
program: program.to_str().unwrap().to_owned(),
args: Vec::new(),
env: Default::default(),
cwd: None,
uid: None,
gid: None,
saw_nul: false,
closures: Vec::new(),
stdin: None,
stdout: None,
stderr: None,
}
}
pub fn arg(&mut self, arg: &OsStr) {
self.args.push(arg.to_str().unwrap().to_owned());
}
pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
&mut self.env
}
pub fn cwd(&mut self, dir: &OsStr) {
self.cwd = Some(dir.to_str().unwrap().to_owned());
}
pub fn uid(&mut self, id: u32) {
self.uid = Some(id);
}
pub fn gid(&mut self, id: u32) {
self.gid = Some(id);
}
pub unsafe fn pre_exec(
&mut self,
f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>,
) {
self.closures.push(f);
}
pub fn stdin(&mut self, stdin: Stdio) {
self.stdin = Some(stdin);
}
pub fn stdout(&mut self, stdout: Stdio) {
self.stdout = Some(stdout);
}
pub fn stderr(&mut self, stderr: Stdio) {
self.stderr = Some(stderr);
}
pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
-> io::Result<(Process, StdioPipes)> {
const CLOEXEC_MSG_FOOTER: &[u8] = b"NOEX";
if self.saw_nul {
return Err(io::Error::new(ErrorKind::InvalidInput,
"nul byte found in provided data"));
}
let (ours, theirs) = self.setup_io(default, needs_stdin)?;
let (input, output) = pipe::anon_pipe()?;
let pid = unsafe {
match cvt(syscall::clone(0))? {
0 => {
drop(input);
let Err(err) = self.do_exec(theirs);
let errno = err.raw_os_error().unwrap_or(syscall::EINVAL) as u32;
let bytes = [
(errno >> 24) as u8,
(errno >> 16) as u8,
(errno >> 8) as u8,
(errno >> 0) as u8,
CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1],
CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3]
];
// pipe I/O up to PIPE_BUF bytes should be atomic, and then
// we want to be sure we *don't* run at_exit destructors as
// we're being torn down regardless
assert!(output.write(&bytes).is_ok());
let _ = syscall::exit(1);
panic!("failed to exit");
}
n => n,
}
};
let mut p = Process { pid: pid, status: None };
drop(output);
let mut bytes = [0; 8];
// loop to handle EINTR
loop {
match input.read(&mut bytes) {
Ok(0) => return Ok((p, ours)),
Ok(8) => {
assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]),
"Validation on the CLOEXEC pipe failed: {:?}", bytes);
let errno = combine(&bytes[0.. 4]);
assert!(p.wait().is_ok(),
"wait() should either return Ok or panic");
return Err(Error::from_raw_os_error(errno))
}
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => {
assert!(p.wait().is_ok(),
"wait() should either return Ok or panic");
panic!("the CLOEXEC pipe failed: {:?}", e)
},
Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic
assert!(p.wait().is_ok(),
"wait() should either return Ok or panic");
panic!("short read on the CLOEXEC pipe")
}
}
}
fn combine(arr: &[u8]) -> i32 {
let a = arr[0] as u32;
let b = arr[1] as u32;
let c = arr[2] as u32;
let d = arr[3] as u32;
((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32
}
}
pub fn exec(&mut self, default: Stdio) -> io::Error {
if self.saw_nul {
return io::Error::new(ErrorKind::InvalidInput,
"nul byte found in provided data")
}
match self.setup_io(default, true) {
Ok((_, theirs)) => unsafe {
let Err(e) = self.do_exec(theirs);
e
},
Err(e) => e,
}
}
// And at this point we've reached a special time in the life of the
// child. The child must now be considered hamstrung and unable to
// do anything other than syscalls really. Consider the following
// scenario:
//
// 1. Thread A of process 1 grabs the malloc() mutex
// 2. Thread B of process 1 forks(), creating thread C
// 3. Thread C of process 2 then attempts to malloc()
// 4. The memory of process 2 is the same as the memory of
// process 1, so the mutex is locked.
//
// This situation looks a lot like deadlock, right? It turns out
// that this is what pthread_atfork() takes care of, which is
// presumably implemented across platforms. The first thing that
// threads to *before* forking is to do things like grab the malloc
// mutex, and then after the fork they unlock it.
//
// Despite this information, libnative's spawn has been witnessed to
// deadlock on both macOS and FreeBSD. I'm not entirely sure why, but
// all collected backtraces point at malloc/free traffic in the
// child spawned process.
//
// For this reason, the block of code below should contain 0
// invocations of either malloc of free (or their related friends).
//
// As an example of not having malloc/free traffic, we don't close
// this file descriptor by dropping the FileDesc (which contains an
// allocation). Instead we just close it manually. This will never
// have the drop glue anyway because this code never returns (the
// child will either exec() or invoke syscall::exit)
unsafe fn do_exec(&mut self, stdio: ChildPipes) -> Result<!, io::Error> {
if let Some(fd) = stdio.stderr.fd() {
cvt(syscall::dup2(fd, 2, &[]))?;
let mut flags = cvt(syscall::fcntl(2, syscall::F_GETFD, 0))?;
flags &= ! syscall::O_CLOEXEC;
cvt(syscall::fcntl(2, syscall::F_SETFD, flags))?;
}
if let Some(fd) = stdio.stdout.fd() {
cvt(syscall::dup2(fd, 1, &[]))?;
let mut flags = cvt(syscall::fcntl(1, syscall::F_GETFD, 0))?;
flags &= ! syscall::O_CLOEXEC;
cvt(syscall::fcntl(1, syscall::F_SETFD, flags))?;
}
if let Some(fd) = stdio.stdin.fd() {
cvt(syscall::dup2(fd, 0, &[]))?;
let mut flags = cvt(syscall::fcntl(0, syscall::F_GETFD, 0))?;
flags &= ! syscall::O_CLOEXEC;
cvt(syscall::fcntl(0, syscall::F_SETFD, flags))?;
}
if let Some(g) = self.gid {
cvt(syscall::setregid(g as usize, g as usize))?;
}
if let Some(u) = self.uid {
cvt(syscall::setreuid(u as usize, u as usize))?;
}
if let Some(ref cwd) = self.cwd {
cvt(syscall::chdir(cwd))?;
}
for callback in self.closures.iter_mut() {
callback()?;
}
self.env.apply();
let program = if self.program.contains(':') || self.program.contains('/') {
Some(PathBuf::from(&self.program))
} else if let Ok(path_env) = env::var("PATH") {
let mut program = None;
for mut path in split_paths(&path_env) {
path.push(&self.program);
if path.exists() {
program = Some(path);
break;
}
}
program
} else {
None
};
let mut file = if let Some(program) = program {
File::open(program.as_os_str())?
} else {
return Err(io::Error::from_raw_os_error(syscall::ENOENT));
};
// Push all the arguments
let mut args: Vec<[usize; 2]> = Vec::with_capacity(1 + self.args.len());
let interpreter = {
let mut reader = BufReader::new(&file);
let mut shebang = [0; 2];
let mut read = 0;
loop {
match reader.read(&mut shebang[read..])? {
0 => break,
n => read += n,
}
}
if &shebang == b"#!" {
// This is an interpreted script.
// First of all, since we'll be passing another file to
// fexec(), we need to manually check that we have permission
// to execute this file:
let uid = cvt(syscall::getuid())?;
let gid = cvt(syscall::getgid())?;
let meta = file.metadata()?;
let mode = if uid == meta.uid() as usize {
meta.mode() >> 3*2 & 0o7
} else if gid == meta.gid() as usize {
meta.mode() >> 3*1 & 0o7
} else {
meta.mode() & 0o7
};
if mode & 1 == 0 {
return Err(io::Error::from_raw_os_error(syscall::EPERM));
}
// Second of all, we need to actually read which interpreter it wants
let mut interpreter = Vec::new();
reader.read_until(b'\n', &mut interpreter)?;
// Pop one trailing newline, if any
if interpreter.ends_with(&[b'\n']) {
interpreter.pop().unwrap();
}
// FIXME: Here we could just reassign `file` directly, if it
// wasn't for lexical lifetimes. Remove the whole `let
// interpreter = { ... };` hack once NLL lands.
// NOTE: Although DO REMEMBER to make sure the interpreter path
// still lives long enough to reach fexec.
Some(interpreter)
} else {
None
}
};
if let Some(ref interpreter) = interpreter {
let path: &OsStr = OsStr::from_bytes(&interpreter);
file = File::open(path)?;
args.push([interpreter.as_ptr() as usize, interpreter.len()]);
} else {
file.seek(SeekFrom::Start(0))?;
}
args.push([self.program.as_ptr() as usize, self.program.len()]);
args.extend(self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()]));
// Push all the variables
let mut vars: Vec<[usize; 2]> = Vec::new();
{
let _guard = ENV_LOCK.lock();
let mut environ = *environ();
while *environ != ptr::null() {
let var = CStr::from_ptr(*environ).to_bytes();
vars.push([var.as_ptr() as usize, var.len()]);
environ = environ.offset(1);
}
}
if let Err(err) = syscall::fexec(file.as_raw_fd(), &args, &vars) {
Err(io::Error::from_raw_os_error(err.errno as i32))
} else {
panic!("return from exec without err");
}
}
fn setup_io(&self, default: Stdio, needs_stdin: bool)
-> io::Result<(StdioPipes, ChildPipes)> {
let null = Stdio::Null;
let default_stdin = if needs_stdin {&default} else {&null};
let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
let stdout = self.stdout.as_ref().unwrap_or(&default);
let stderr = self.stderr.as_ref().unwrap_or(&default);
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,
};
Ok((ours, theirs))
}
}
impl Stdio {
fn to_child_stdio(&self, readable: bool)
-> io::Result<(ChildStdio, Option<AnonPipe>)> {
match *self {
Stdio::Inherit => Ok((ChildStdio::Inherit, None)),
// Make sure that the source descriptors are not an stdio
// descriptor, otherwise the order which we set the child's
// descriptors may blow away a descriptor which we are hoping to
// save. For example, suppose we want the child's stderr to be the
// parent's stdout, and the child's stdout to be the parent's
// stderr. No matter which we dup first, the second will get
// overwritten prematurely.
Stdio::Fd(ref fd) => {
if fd.raw() <= 2 {
Ok((ChildStdio::Owned(fd.duplicate()?), None))
} else {
Ok((ChildStdio::Explicit(fd.raw()), None))
}
}
Stdio::MakePipe => {
let (reader, writer) = pipe::anon_pipe()?;
let (ours, theirs) = if readable {
(writer, reader)
} else {
(reader, writer)
};
Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
}
Stdio::Null => {
let mut opts = OpenOptions::new();
opts.read(readable);
opts.write(!readable);
let fd = SysFile::open(Path::new("null:"), &opts)?;
Ok((ChildStdio::Owned(fd.into_fd()), None))
}
}
}
}
impl From<AnonPipe> for Stdio {
fn from(pipe: AnonPipe) -> Stdio {
Stdio::Fd(pipe.into_fd())
}
}
impl From<SysFile> for Stdio {
fn from(file: SysFile) -> Stdio {
Stdio::Fd(file.into_fd())
}
}
impl ChildStdio {
fn fd(&self) -> Option<usize> {
match *self {
ChildStdio::Inherit => None,
ChildStdio::Explicit(fd) => Some(fd),
ChildStdio::Owned(ref fd) => Some(fd.raw()),
}
}
}
impl fmt::Debug for Command {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.program)?;
for arg in &self.args {
write!(f, " {:?}", arg)?;
}
Ok(())
}
}
////////////////////////////////////////////////////////////////////////////////
// Processes
////////////////////////////////////////////////////////////////////////////////
/// Unix exit statuses
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitStatus(i32);
impl ExitStatus {
fn exited(&self) -> bool {
self.0 & 0x7F == 0
}
pub fn success(&self) -> bool {
self.code() == Some(0)
}
pub fn code(&self) -> Option<i32> {
if self.exited() {
Some((self.0 >> 8) & 0xFF)
} else {
None
}
}
pub fn signal(&self) -> Option<i32> {
if !self.exited() {
Some(self.0 & 0x7F)
} else {
None
}
}
}
impl From<i32> for ExitStatus {
fn from(a: i32) -> ExitStatus {
ExitStatus(a)
}
}
impl fmt::Display for ExitStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(code) = self.code() {
write!(f, "exit code: {}", code)
} else {
let signal = self.signal().unwrap();
write!(f, "signal: {}", signal)
}
}
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitCode(u8);
impl ExitCode {
pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
pub fn as_i32(&self) -> i32 {
self.0 as i32
}
}
/// The unique ID of the process (this should never be negative).
pub struct Process {
pid: usize,
status: Option<ExitStatus>,
}
impl Process {
pub fn id(&self) -> u32 {
self.pid as u32
}
pub fn kill(&mut self) -> io::Result<()> {
// If we've already waited on this process then the pid can be recycled
// and used for another process, and we probably shouldn't be killing
// random processes, so just return an error.
if self.status.is_some() {
Err(Error::new(ErrorKind::InvalidInput,
"invalid argument: can't kill an exited process"))
} else {
cvt(syscall::kill(self.pid, syscall::SIGKILL))?;
Ok(())
}
}
pub fn wait(&mut self) -> io::Result<ExitStatus> {
if let Some(status) = self.status {
return Ok(status)
}
let mut status = 0;
cvt(syscall::waitpid(self.pid, &mut status, 0))?;
self.status = Some(ExitStatus(status as i32));
Ok(ExitStatus(status as i32))
}
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
if let Some(status) = self.status {
return Ok(Some(status))
}
let mut status = 0;
let pid = cvt(syscall::waitpid(self.pid, &mut status, syscall::WNOHANG))?;
if pid == 0 {
Ok(None)
} else {
self.status = Some(ExitStatus(status as i32));
Ok(Some(ExitStatus(status as i32)))
}
}
}

View File

@ -1,3 +0,0 @@
pub fn hashmap_random_keys() -> (u64, u64) {
(0, 0)
}

View File

@ -1,51 +0,0 @@
use super::mutex::Mutex;
pub struct RWLock {
mutex: Mutex
}
unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {}
impl RWLock {
pub const fn new() -> RWLock {
RWLock {
mutex: Mutex::new()
}
}
#[inline]
pub unsafe fn read(&self) {
self.mutex.lock();
}
#[inline]
pub unsafe fn try_read(&self) -> bool {
self.mutex.try_lock()
}
#[inline]
pub unsafe fn write(&self) {
self.mutex.lock();
}
#[inline]
pub unsafe fn try_write(&self) -> bool {
self.mutex.try_lock()
}
#[inline]
pub unsafe fn read_unlock(&self) {
self.mutex.unlock();
}
#[inline]
pub unsafe fn write_unlock(&self) {
self.mutex.unlock();
}
#[inline]
pub unsafe fn destroy(&self) {
self.mutex.destroy();
}
}

View File

@ -1,17 +0,0 @@
#![cfg_attr(test, allow(dead_code))]
pub struct Handler;
impl Handler {
pub unsafe fn new() -> Handler {
Handler
}
}
pub unsafe fn init() {
}
pub unsafe fn cleanup() {
}

View File

@ -1,64 +0,0 @@
use crate::io;
use crate::sys::{cvt, syscall};
use crate::sys::fd::FileDesc;
pub struct Stdin(());
pub struct Stdout(());
pub struct Stderr(());
impl Stdin {
pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
}
impl io::Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let fd = FileDesc::new(0);
let ret = fd.read(buf);
fd.into_raw();
ret
}
}
impl Stdout {
pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
}
impl io::Write for Stdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let fd = FileDesc::new(1);
let ret = fd.write(buf);
fd.into_raw();
ret
}
fn flush(&mut self) -> io::Result<()> {
cvt(syscall::fsync(1)).and(Ok(()))
}
}
impl Stderr {
pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
}
impl io::Write for Stderr {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let fd = FileDesc::new(2);
let ret = fd.write(buf);
fd.into_raw();
ret
}
fn flush(&mut self) -> io::Result<()> {
cvt(syscall::fsync(2)).and(Ok(()))
}
}
pub fn is_ebadf(err: &io::Error) -> bool {
err.raw_os_error() == Some(crate::sys::syscall::EBADF as i32)
}
pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
pub fn panic_output() -> Option<impl io::Write> {
Stderr::new().ok()
}

View File

@ -1,73 +0,0 @@
use super::error::{Error, Result};
pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
asm!("swi $$0"
: "={r0}"(a)
: "{r7}"(a)
: "memory"
: "volatile");
Error::demux(a)
}
pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
asm!("swi $$0"
: "={r0}"(a)
: "{r7}"(a), "{r0}"(b)
: "memory"
: "volatile");
Error::demux(a)
}
// Clobbers all registers - special for clone
pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
asm!("swi $$0"
: "={r0}"(a)
: "{r7}"(a), "{r0}"(b)
: "memory", "r0", "r1", "r2", "r3", "r4"
: "volatile");
Error::demux(a)
}
pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
asm!("swi $$0"
: "={r0}"(a)
: "{r7}"(a), "{r0}"(b), "{r1}"(c)
: "memory"
: "volatile");
Error::demux(a)
}
pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
asm!("swi $$0"
: "={r0}"(a)
: "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d)
: "memory"
: "volatile");
Error::demux(a)
}
pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
asm!("swi $$0"
: "={r0}"(a)
: "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e)
: "memory"
: "volatile");
Error::demux(a)
}
pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
-> Result<usize> {
asm!("swi $$0"
: "={r0}"(a)
: "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e), "{r4}"(f)
: "memory"
: "volatile");
Error::demux(a)
}

View File

@ -1,73 +0,0 @@
use super::error::{Error, Result};
pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
asm!("int 0x80"
: "={eax}"(a)
: "{eax}"(a)
: "memory"
: "intel", "volatile");
Error::demux(a)
}
pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
asm!("int 0x80"
: "={eax}"(a)
: "{eax}"(a), "{ebx}"(b)
: "memory"
: "intel", "volatile");
Error::demux(a)
}
// Clobbers all registers - special for clone
pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
asm!("int 0x80"
: "={eax}"(a)
: "{eax}"(a), "{ebx}"(b)
: "memory", "ebx", "ecx", "edx", "esi", "edi"
: "intel", "volatile");
Error::demux(a)
}
pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
asm!("int 0x80"
: "={eax}"(a)
: "{eax}"(a), "{ebx}"(b), "{ecx}"(c)
: "memory"
: "intel", "volatile");
Error::demux(a)
}
pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
asm!("int 0x80"
: "={eax}"(a)
: "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d)
: "memory"
: "intel", "volatile");
Error::demux(a)
}
pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
asm!("int 0x80"
: "={eax}"(a)
: "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e)
: "memory"
: "intel", "volatile");
Error::demux(a)
}
pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
-> Result<usize> {
asm!("int 0x80"
: "={eax}"(a)
: "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e), "{edi}"(f)
: "memory"
: "intel", "volatile");
Error::demux(a)
}

View File

@ -1,74 +0,0 @@
use super::error::{Error, Result};
pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
asm!("int 0x80"
: "={rax}"(a)
: "{rax}"(a)
: "memory"
: "intel", "volatile");
Error::demux(a)
}
pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
asm!("int 0x80"
: "={rax}"(a)
: "{rax}"(a), "{rbx}"(b)
: "memory"
: "intel", "volatile");
Error::demux(a)
}
// Clobbers all registers - special for clone
pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
asm!("int 0x80"
: "={rax}"(a)
: "{rax}"(a), "{rbx}"(b)
: "memory", "rbx", "rcx", "rdx", "rsi", "rdi", "r8",
"r9", "r10", "r11", "r12", "r13", "r14", "r15"
: "intel", "volatile");
Error::demux(a)
}
pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
asm!("int 0x80"
: "={rax}"(a)
: "{rax}"(a), "{rbx}"(b), "{rcx}"(c)
: "memory"
: "intel", "volatile");
Error::demux(a)
}
pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
asm!("int 0x80"
: "={rax}"(a)
: "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d)
: "memory"
: "intel", "volatile");
Error::demux(a)
}
pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
asm!("int 0x80"
: "={rax}"(a)
: "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e)
: "memory"
: "intel", "volatile");
Error::demux(a)
}
pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
-> Result<usize> {
asm!("int 0x80"
: "={rax}"(a)
: "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e), "{rdi}"(f)
: "memory"
: "intel", "volatile");
Error::demux(a)
}

View File

@ -1,348 +0,0 @@
use super::arch::*;
use super::data::{SigAction, Stat, StatVfs, TimeSpec};
use super::error::Result;
use super::number::*;
use core::{mem, ptr};
// Signal restorer
extern "C" fn restorer() -> ! {
sigreturn().unwrap();
unreachable!();
}
/// Set the end of the process's heap
///
/// When `addr` is `0`, this function will return the current break.
///
/// When `addr` is nonzero, this function will attempt to set the end of the process's
/// heap to `addr` and return the new program break. The new program break should be
/// checked by the allocator, it may not be exactly `addr`, as it may be aligned to a page
/// boundary.
///
/// On error, `Err(ENOMEM)` will be returned indicating that no memory is available
pub unsafe fn brk(addr: usize) -> Result<usize> {
syscall1(SYS_BRK, addr)
}
/// Changes the process's working directory.
///
/// This function will attempt to set the process's working directory to `path`, which can be
/// either a relative, scheme relative, or absolute path.
///
/// On success, `Ok(0)` will be returned. On error, one of the following errors will be returned.
///
/// # Errors
///
/// * `EACCES` - permission is denied for one of the components of `path`, or `path`
/// * `EFAULT` - `path` does not point to the process's addressable memory
/// * `EIO` - an I/O error occurred
/// * `ENOENT` - `path` does not exit
/// * `ENOTDIR` - `path` is not a directory
pub fn chdir<T: AsRef<[u8]>>(path: T) -> Result<usize> {
unsafe { syscall2(SYS_CHDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
}
pub fn chmod<T: AsRef<[u8]>>(path: T, mode: usize) -> Result<usize> {
unsafe { syscall3(SYS_CHMOD, path.as_ref().as_ptr() as usize, path.as_ref().len(), mode) }
}
/// Produces a fork of the current process, or a new process thread.
pub unsafe fn clone(flags: usize) -> Result<usize> {
syscall1_clobber(SYS_CLONE, flags)
}
/// Closes a file.
pub fn close(fd: usize) -> Result<usize> {
unsafe { syscall1(SYS_CLOSE, fd) }
}
/// Gets the current system time.
pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result<usize> {
unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) }
}
/// Copies and transforms a file descriptor.
pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> {
unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) }
}
/// Copies and transforms a file descriptor.
pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result<usize> {
unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) }
}
/// Exits the current process.
pub fn exit(status: usize) -> Result<usize> {
unsafe { syscall1(SYS_EXIT, status) }
}
/// Changes file permissions.
pub fn fchmod(fd: usize, mode: u16) -> Result<usize> {
unsafe { syscall2(SYS_FCHMOD, fd, mode as usize) }
}
/// Changes file ownership.
pub fn fchown(fd: usize, uid: u32, gid: u32) -> Result<usize> {
unsafe { syscall3(SYS_FCHOWN, fd, uid as usize, gid as usize) }
}
/// Changes file descriptor flags.
pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result<usize> {
unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) }
}
/// Replaces the current process with a new executable.
pub fn fexec(fd: usize, args: &[[usize; 2]], vars: &[[usize; 2]]) -> Result<usize> {
unsafe { syscall5(SYS_FEXEC, fd, args.as_ptr() as usize, args.len(),
vars.as_ptr() as usize, vars.len()) }
}
/// Maps a file into memory.
pub unsafe fn fmap(fd: usize, offset: usize, size: usize) -> Result<usize> {
syscall3(SYS_FMAP, fd, offset, size)
}
/// Unmaps a memory-mapped file.
pub unsafe fn funmap(addr: usize) -> Result<usize> {
syscall1(SYS_FUNMAP, addr)
}
/// Retrieves the canonical path of a file.
pub fn fpath(fd: usize, buf: &mut [u8]) -> Result<usize> {
unsafe { syscall3(SYS_FPATH, fd, buf.as_mut_ptr() as usize, buf.len()) }
}
/// Renames a file.
pub fn frename<T: AsRef<[u8]>>(fd: usize, path: T) -> Result<usize> {
unsafe { syscall3(SYS_FRENAME, fd, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
}
/// Gets metadata about a file.
pub fn fstat(fd: usize, stat: &mut Stat) -> Result<usize> {
unsafe { syscall3(SYS_FSTAT, fd, stat as *mut Stat as usize, mem::size_of::<Stat>()) }
}
/// Gets metadata about a filesystem.
pub fn fstatvfs(fd: usize, stat: &mut StatVfs) -> Result<usize> {
unsafe { syscall3(SYS_FSTATVFS, fd, stat as *mut StatVfs as usize, mem::size_of::<StatVfs>()) }
}
/// Syncs a file descriptor to its underlying medium.
pub fn fsync(fd: usize) -> Result<usize> {
unsafe { syscall1(SYS_FSYNC, fd) }
}
/// Truncate or extend a file to a specified length
pub fn ftruncate(fd: usize, len: usize) -> Result<usize> {
unsafe { syscall2(SYS_FTRUNCATE, fd, len) }
}
// Change modify and/or access times
pub fn futimens(fd: usize, times: &[TimeSpec]) -> Result<usize> {
unsafe { syscall3(SYS_FUTIMENS, fd, times.as_ptr() as usize,
times.len() * mem::size_of::<TimeSpec>()) }
}
/// Fast userspace mutex
pub unsafe fn futex(addr: *mut i32, op: usize, val: i32, val2: usize, addr2: *mut i32)
-> Result<usize> {
syscall5(SYS_FUTEX, addr as usize, op, (val as isize) as usize, val2, addr2 as usize)
}
/// Gets the current working directory.
pub fn getcwd(buf: &mut [u8]) -> Result<usize> {
unsafe { syscall2(SYS_GETCWD, buf.as_mut_ptr() as usize, buf.len()) }
}
/// Gets the effective group ID.
pub fn getegid() -> Result<usize> {
unsafe { syscall0(SYS_GETEGID) }
}
/// Gets the effective namespace.
pub fn getens() -> Result<usize> {
unsafe { syscall0(SYS_GETENS) }
}
/// Gets the effective user ID.
pub fn geteuid() -> Result<usize> {
unsafe { syscall0(SYS_GETEUID) }
}
/// Gets the current group ID.
pub fn getgid() -> Result<usize> {
unsafe { syscall0(SYS_GETGID) }
}
/// Gets the current namespace.
pub fn getns() -> Result<usize> {
unsafe { syscall0(SYS_GETNS) }
}
/// Gets the current process ID.
pub fn getpid() -> Result<usize> {
unsafe { syscall0(SYS_GETPID) }
}
/// Gets the process group ID.
pub fn getpgid(pid: usize) -> Result<usize> {
unsafe { syscall1(SYS_GETPGID, pid) }
}
/// Gets the parent process ID.
pub fn getppid() -> Result<usize> {
unsafe { syscall0(SYS_GETPPID) }
}
/// Gets the current user ID.
pub fn getuid() -> Result<usize> {
unsafe { syscall0(SYS_GETUID) }
}
/// Sets the I/O privilege level
pub unsafe fn iopl(level: usize) -> Result<usize> {
syscall1(SYS_IOPL, level)
}
/// Sends a signal `sig` to the process identified by `pid`.
pub fn kill(pid: usize, sig: usize) -> Result<usize> {
unsafe { syscall2(SYS_KILL, pid, sig) }
}
/// Creates a link to a file.
pub unsafe fn link(old: *const u8, new: *const u8) -> Result<usize> {
syscall2(SYS_LINK, old as usize, new as usize)
}
/// Seeks to `offset` bytes in a file descriptor.
pub fn lseek(fd: usize, offset: isize, whence: usize) -> Result<usize> {
unsafe { syscall3(SYS_LSEEK, fd, offset as usize, whence) }
}
/// Makes a new scheme namespace.
pub fn mkns(schemes: &[[usize; 2]]) -> Result<usize> {
unsafe { syscall2(SYS_MKNS, schemes.as_ptr() as usize, schemes.len()) }
}
/// Sleeps for the time specified in `req`.
pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result<usize> {
unsafe { syscall2(SYS_NANOSLEEP, req as *const TimeSpec as usize,
rem as *mut TimeSpec as usize) }
}
/// Opens a file.
pub fn open<T: AsRef<[u8]>>(path: T, flags: usize) -> Result<usize> {
unsafe { syscall3(SYS_OPEN, path.as_ref().as_ptr() as usize, path.as_ref().len(), flags) }
}
/// Allocates pages, linearly in physical memory.
pub unsafe fn physalloc(size: usize) -> Result<usize> {
syscall1(SYS_PHYSALLOC, size)
}
/// Frees physically allocated pages.
pub unsafe fn physfree(physical_address: usize, size: usize) -> Result<usize> {
syscall2(SYS_PHYSFREE, physical_address, size)
}
/// Maps physical memory to virtual memory.
pub unsafe fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> {
syscall3(SYS_PHYSMAP, physical_address, size, flags)
}
/// Unmaps previously mapped physical memory.
pub unsafe fn physunmap(virtual_address: usize) -> Result<usize> {
syscall1(SYS_PHYSUNMAP, virtual_address)
}
/// Creates a pair of file descriptors referencing the read and write ends of a pipe.
pub fn pipe2(fds: &mut [usize; 2], flags: usize) -> Result<usize> {
unsafe { syscall2(SYS_PIPE2, fds.as_ptr() as usize, flags) }
}
/// Read from a file descriptor into a buffer
pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> {
unsafe { syscall3(SYS_READ, fd, buf.as_mut_ptr() as usize, buf.len()) }
}
/// Removes a directory.
pub fn rmdir<T: AsRef<[u8]>>(path: T) -> Result<usize> {
unsafe { syscall2(SYS_RMDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
}
/// Sets the process group ID.
pub fn setpgid(pid: usize, pgid: usize) -> Result<usize> {
unsafe { syscall2(SYS_SETPGID, pid, pgid) }
}
/// Sets the current process group IDs.
pub fn setregid(rgid: usize, egid: usize) -> Result<usize> {
unsafe { syscall2(SYS_SETREGID, rgid, egid) }
}
/// Makes a new scheme namespace.
pub fn setrens(rns: usize, ens: usize) -> Result<usize> {
unsafe { syscall2(SYS_SETRENS, rns, ens) }
}
/// Sets the current process user IDs.
pub fn setreuid(ruid: usize, euid: usize) -> Result<usize> {
unsafe { syscall2(SYS_SETREUID, ruid, euid) }
}
/// Sets up a signal handler.
pub fn sigaction(sig: usize, act: Option<&SigAction>, oldact: Option<&mut SigAction>)
-> Result<usize> {
unsafe { syscall4(SYS_SIGACTION, sig,
act.map(|x| x as *const _).unwrap_or_else(ptr::null) as usize,
oldact.map(|x| x as *mut _).unwrap_or_else(ptr::null_mut) as usize,
restorer as usize) }
}
/// Returns from signal handler.
pub fn sigreturn() -> Result<usize> {
unsafe { syscall0(SYS_SIGRETURN) }
}
/// Removes a file.
pub fn unlink<T: AsRef<[u8]>>(path: T) -> Result<usize> {
unsafe { syscall2(SYS_UNLINK, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
}
/// Converts a virtual address to a physical one.
pub unsafe fn virttophys(virtual_address: usize) -> Result<usize> {
syscall1(SYS_VIRTTOPHYS, virtual_address)
}
/// Checks if a child process has exited or received a signal.
pub fn waitpid(pid: usize, status: &mut usize, options: usize) -> Result<usize> {
unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options) }
}
/// Writes a buffer to a file descriptor.
///
/// The kernel will attempt to write the bytes in `buf` to the file descriptor `fd`, returning
/// either an `Err`, explained below, or `Ok(count)` where `count` is the number of bytes which
/// were written.
///
/// # Errors
///
/// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block
/// * `EBADF` - the file descriptor is not valid or is not open for writing
/// * `EFAULT` - `buf` does not point to the process's addressable memory
/// * `EIO` - an I/O error occurred
/// * `ENOSPC` - the device containing the file descriptor has no room for data
/// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed
pub fn write(fd: usize, buf: &[u8]) -> Result<usize> {
unsafe { syscall3(SYS_WRITE, fd, buf.as_ptr() as usize, buf.len()) }
}
/// Yields the process's time slice to the kernel.
///
/// This function will return Ok(0) on success
pub fn sched_yield() -> Result<usize> {
unsafe { syscall0(SYS_YIELD) }
}

View File

@ -1,191 +0,0 @@
use core::ops::{Deref, DerefMut};
use core::{mem, slice};
#[derive(Copy, Clone, Debug, Default)]
pub struct Event {
pub id: usize,
pub flags: usize,
pub data: usize
}
impl Deref for Event {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
slice::from_raw_parts(
self as *const Event as *const u8,
mem::size_of::<Event>()
) as &[u8]
}
}
}
impl DerefMut for Event {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe {
slice::from_raw_parts_mut(
self as *mut Event as *mut u8,
mem::size_of::<Event>()
) as &mut [u8]
}
}
}
#[derive(Copy, Clone, Debug, Default)]
#[repr(C)]
pub struct Packet {
pub id: u64,
pub pid: usize,
pub uid: u32,
pub gid: u32,
pub a: usize,
pub b: usize,
pub c: usize,
pub d: usize
}
impl Deref for Packet {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
slice::from_raw_parts(
self as *const Packet as *const u8,
mem::size_of::<Packet>()
) as &[u8]
}
}
}
impl DerefMut for Packet {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe {
slice::from_raw_parts_mut(
self as *mut Packet as *mut u8,
mem::size_of::<Packet>()
) as &mut [u8]
}
}
}
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct SigAction {
pub sa_handler: extern "C" fn(usize),
pub sa_mask: [u64; 2],
pub sa_flags: usize,
}
impl Default for SigAction {
fn default() -> Self {
Self {
sa_handler: unsafe { mem::transmute(0usize) },
sa_mask: [0; 2],
sa_flags: 0,
}
}
}
#[derive(Copy, Clone, Debug, Default)]
#[repr(C)]
pub struct Stat {
pub st_dev: u64,
pub st_ino: u64,
pub st_mode: u16,
pub st_nlink: u32,
pub st_uid: u32,
pub st_gid: u32,
pub st_size: u64,
pub st_blksize: u32,
pub st_blocks: u64,
pub st_mtime: u64,
pub st_mtime_nsec: u32,
pub st_atime: u64,
pub st_atime_nsec: u32,
pub st_ctime: u64,
pub st_ctime_nsec: u32,
}
impl Deref for Stat {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
slice::from_raw_parts(
self as *const Stat as *const u8,
mem::size_of::<Stat>()
) as &[u8]
}
}
}
impl DerefMut for Stat {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe {
slice::from_raw_parts_mut(
self as *mut Stat as *mut u8,
mem::size_of::<Stat>()
) as &mut [u8]
}
}
}
#[derive(Copy, Clone, Debug, Default)]
#[repr(C)]
pub struct StatVfs {
pub f_bsize: u32,
pub f_blocks: u64,
pub f_bfree: u64,
pub f_bavail: u64,
}
impl Deref for StatVfs {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
slice::from_raw_parts(
self as *const StatVfs as *const u8,
mem::size_of::<StatVfs>()
) as &[u8]
}
}
}
impl DerefMut for StatVfs {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe {
slice::from_raw_parts_mut(
self as *mut StatVfs as *mut u8,
mem::size_of::<StatVfs>()
) as &mut [u8]
}
}
}
#[derive(Copy, Clone, Debug, Default)]
#[repr(C)]
pub struct TimeSpec {
pub tv_sec: i64,
pub tv_nsec: i32,
}
impl Deref for TimeSpec {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
slice::from_raw_parts(
self as *const TimeSpec as *const u8,
mem::size_of::<TimeSpec>()
) as &[u8]
}
}
}
impl DerefMut for TimeSpec {
fn deref_mut(&mut self) -> &mut [u8] {
unsafe {
slice::from_raw_parts_mut(
self as *mut TimeSpec as *mut u8,
mem::size_of::<TimeSpec>()
) as &mut [u8]
}
}
}

View File

@ -1,315 +0,0 @@
use core::{fmt, result};
#[derive(Eq, PartialEq)]
pub struct Error {
pub errno: i32,
}
pub type Result<T> = result::Result<T, Error>;
impl Error {
pub fn new(errno: i32) -> Error {
Error { errno }
}
pub fn mux(result: Result<usize>) -> usize {
match result {
Ok(value) => value,
Err(error) => -error.errno as usize,
}
}
pub fn demux(value: usize) -> Result<usize> {
let errno = -(value as i32);
if errno >= 1 && errno < STR_ERROR.len() as i32 {
Err(Error::new(errno))
} else {
Ok(value)
}
}
pub fn text(&self) -> &str {
if let Some(description) = STR_ERROR.get(self.errno as usize) {
description
} else {
"Unknown Error"
}
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.text())
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.text())
}
}
pub const EPERM: i32 = 1; /* Operation not permitted */
pub const ENOENT: i32 = 2; /* No such file or directory */
pub const ESRCH: i32 = 3; /* No such process */
pub const EINTR: i32 = 4; /* Interrupted system call */
pub const EIO: i32 = 5; /* I/O error */
pub const ENXIO: i32 = 6; /* No such device or address */
pub const E2BIG: i32 = 7; /* Argument list too long */
pub const ENOEXEC: i32 = 8; /* Exec format error */
pub const EBADF: i32 = 9; /* Bad file number */
pub const ECHILD: i32 = 10; /* No child processes */
pub const EAGAIN: i32 = 11; /* Try again */
pub const ENOMEM: i32 = 12; /* Out of memory */
pub const EACCES: i32 = 13; /* Permission denied */
pub const EFAULT: i32 = 14; /* Bad address */
pub const ENOTBLK: i32 = 15; /* Block device required */
pub const EBUSY: i32 = 16; /* Device or resource busy */
pub const EEXIST: i32 = 17; /* File exists */
pub const EXDEV: i32 = 18; /* Cross-device link */
pub const ENODEV: i32 = 19; /* No such device */
pub const ENOTDIR: i32 = 20; /* Not a directory */
pub const EISDIR: i32 = 21; /* Is a directory */
pub const EINVAL: i32 = 22; /* Invalid argument */
pub const ENFILE: i32 = 23; /* File table overflow */
pub const EMFILE: i32 = 24; /* Too many open files */
pub const ENOTTY: i32 = 25; /* Not a typewriter */
pub const ETXTBSY: i32 = 26; /* Text file busy */
pub const EFBIG: i32 = 27; /* File too large */
pub const ENOSPC: i32 = 28; /* No space left on device */
pub const ESPIPE: i32 = 29; /* Illegal seek */
pub const EROFS: i32 = 30; /* Read-only file system */
pub const EMLINK: i32 = 31; /* Too many links */
pub const EPIPE: i32 = 32; /* Broken pipe */
pub const EDOM: i32 = 33; /* Math argument out of domain of func */
pub const ERANGE: i32 = 34; /* Math result not representable */
pub const EDEADLK: i32 = 35; /* Resource deadlock would occur */
pub const ENAMETOOLONG: i32 = 36; /* File name too long */
pub const ENOLCK: i32 = 37; /* No record locks available */
pub const ENOSYS: i32 = 38; /* Function not implemented */
pub const ENOTEMPTY: i32 = 39; /* Directory not empty */
pub const ELOOP: i32 = 40; /* Too many symbolic links encountered */
pub const EWOULDBLOCK: i32 = 41; /* Operation would block */
pub const ENOMSG: i32 = 42; /* No message of desired type */
pub const EIDRM: i32 = 43; /* Identifier removed */
pub const ECHRNG: i32 = 44; /* Channel number out of range */
pub const EL2NSYNC: i32 = 45; /* Level 2 not synchronized */
pub const EL3HLT: i32 = 46; /* Level 3 halted */
pub const EL3RST: i32 = 47; /* Level 3 reset */
pub const ELNRNG: i32 = 48; /* Link number out of range */
pub const EUNATCH: i32 = 49; /* Protocol driver not attached */
pub const ENOCSI: i32 = 50; /* No CSI structure available */
pub const EL2HLT: i32 = 51; /* Level 2 halted */
pub const EBADE: i32 = 52; /* Invalid exchange */
pub const EBADR: i32 = 53; /* Invalid request descriptor */
pub const EXFULL: i32 = 54; /* Exchange full */
pub const ENOANO: i32 = 55; /* No anode */
pub const EBADRQC: i32 = 56; /* Invalid request code */
pub const EBADSLT: i32 = 57; /* Invalid slot */
pub const EDEADLOCK: i32 = 58; /* Resource deadlock would occur */
pub const EBFONT: i32 = 59; /* Bad font file format */
pub const ENOSTR: i32 = 60; /* Device not a stream */
pub const ENODATA: i32 = 61; /* No data available */
pub const ETIME: i32 = 62; /* Timer expired */
pub const ENOSR: i32 = 63; /* Out of streams resources */
pub const ENONET: i32 = 64; /* Machine is not on the network */
pub const ENOPKG: i32 = 65; /* Package not installed */
pub const EREMOTE: i32 = 66; /* Object is remote */
pub const ENOLINK: i32 = 67; /* Link has been severed */
pub const EADV: i32 = 68; /* Advertise error */
pub const ESRMNT: i32 = 69; /* Srmount error */
pub const ECOMM: i32 = 70; /* Communication error on send */
pub const EPROTO: i32 = 71; /* Protocol error */
pub const EMULTIHOP: i32 = 72; /* Multihop attempted */
pub const EDOTDOT: i32 = 73; /* RFS specific error */
pub const EBADMSG: i32 = 74; /* Not a data message */
pub const EOVERFLOW: i32 = 75; /* Value too large for defined data type */
pub const ENOTUNIQ: i32 = 76; /* Name not unique on network */
pub const EBADFD: i32 = 77; /* File descriptor in bad state */
pub const EREMCHG: i32 = 78; /* Remote address changed */
pub const ELIBACC: i32 = 79; /* Can not access a needed shared library */
pub const ELIBBAD: i32 = 80; /* Accessing a corrupted shared library */
pub const ELIBSCN: i32 = 81; /* .lib section in a.out corrupted */
pub const ELIBMAX: i32 = 82; /* Attempting to link in too many shared libraries */
pub const ELIBEXEC: i32 = 83; /* Cannot exec a shared library directly */
pub const EILSEQ: i32 = 84; /* Illegal byte sequence */
pub const ERESTART: i32 = 85; /* Interrupted system call should be restarted */
pub const ESTRPIPE: i32 = 86; /* Streams pipe error */
pub const EUSERS: i32 = 87; /* Too many users */
pub const ENOTSOCK: i32 = 88; /* Socket operation on non-socket */
pub const EDESTADDRREQ: i32 = 89; /* Destination address required */
pub const EMSGSIZE: i32 = 90; /* Message too long */
pub const EPROTOTYPE: i32 = 91; /* Protocol wrong type for socket */
pub const ENOPROTOOPT: i32 = 92; /* Protocol not available */
pub const EPROTONOSUPPORT: i32 = 93; /* Protocol not supported */
pub const ESOCKTNOSUPPORT: i32 = 94; /* Socket type not supported */
pub const EOPNOTSUPP: i32 = 95; /* Operation not supported on transport endpoint */
pub const EPFNOSUPPORT: i32 = 96; /* Protocol family not supported */
pub const EAFNOSUPPORT: i32 = 97; /* Address family not supported by protocol */
pub const EADDRINUSE: i32 = 98; /* Address already in use */
pub const EADDRNOTAVAIL: i32 = 99; /* Cannot assign requested address */
pub const ENETDOWN: i32 = 100; /* Network is down */
pub const ENETUNREACH: i32 = 101; /* Network is unreachable */
pub const ENETRESET: i32 = 102; /* Network dropped connection because of reset */
pub const ECONNABORTED: i32 = 103; /* Software caused connection abort */
pub const ECONNRESET: i32 = 104; /* Connection reset by peer */
pub const ENOBUFS: i32 = 105; /* No buffer space available */
pub const EISCONN: i32 = 106; /* Transport endpoint is already connected */
pub const ENOTCONN: i32 = 107; /* Transport endpoint is not connected */
pub const ESHUTDOWN: i32 = 108; /* Cannot send after transport endpoint shutdown */
pub const ETOOMANYREFS: i32 = 109; /* Too many references: cannot splice */
pub const ETIMEDOUT: i32 = 110; /* Connection timed out */
pub const ECONNREFUSED: i32 = 111; /* Connection refused */
pub const EHOSTDOWN: i32 = 112; /* Host is down */
pub const EHOSTUNREACH: i32 = 113; /* No route to host */
pub const EALREADY: i32 = 114; /* Operation already in progress */
pub const EINPROGRESS: i32 = 115; /* Operation now in progress */
pub const ESTALE: i32 = 116; /* Stale NFS file handle */
pub const EUCLEAN: i32 = 117; /* Structure needs cleaning */
pub const ENOTNAM: i32 = 118; /* Not a XENIX named type file */
pub const ENAVAIL: i32 = 119; /* No XENIX semaphores available */
pub const EISNAM: i32 = 120; /* Is a named type file */
pub const EREMOTEIO: i32 = 121; /* Remote I/O error */
pub const EDQUOT: i32 = 122; /* Quota exceeded */
pub const ENOMEDIUM: i32 = 123; /* No medium found */
pub const EMEDIUMTYPE: i32 = 124; /* Wrong medium type */
pub const ECANCELED: i32 = 125; /* Operation Canceled */
pub const ENOKEY: i32 = 126; /* Required key not available */
pub const EKEYEXPIRED: i32 = 127; /* Key has expired */
pub const EKEYREVOKED: i32 = 128; /* Key has been revoked */
pub const EKEYREJECTED: i32 = 129; /* Key was rejected by service */
pub const EOWNERDEAD: i32 = 130; /* Owner died */
pub const ENOTRECOVERABLE: i32 = 131; /* State not recoverable */
pub static STR_ERROR: [&'static str; 132] = ["Success",
"Operation not permitted",
"No such file or directory",
"No such process",
"Interrupted system call",
"I/O error",
"No such device or address",
"Argument list too long",
"Exec format error",
"Bad file number",
"No child processes",
"Try again",
"Out of memory",
"Permission denied",
"Bad address",
"Block device required",
"Device or resource busy",
"File exists",
"Cross-device link",
"No such device",
"Not a directory",
"Is a directory",
"Invalid argument",
"File table overflow",
"Too many open files",
"Not a typewriter",
"Text file busy",
"File too large",
"No space left on device",
"Illegal seek",
"Read-only file system",
"Too many links",
"Broken pipe",
"Math argument out of domain of func",
"Math result not representable",
"Resource deadlock would occur",
"File name too long",
"No record locks available",
"Function not implemented",
"Directory not empty",
"Too many symbolic links encountered",
"Operation would block",
"No message of desired type",
"Identifier removed",
"Channel number out of range",
"Level 2 not synchronized",
"Level 3 halted",
"Level 3 reset",
"Link number out of range",
"Protocol driver not attached",
"No CSI structure available",
"Level 2 halted",
"Invalid exchange",
"Invalid request descriptor",
"Exchange full",
"No anode",
"Invalid request code",
"Invalid slot",
"Resource deadlock would occur",
"Bad font file format",
"Device not a stream",
"No data available",
"Timer expired",
"Out of streams resources",
"Machine is not on the network",
"Package not installed",
"Object is remote",
"Link has been severed",
"Advertise error",
"Srmount error",
"Communication error on send",
"Protocol error",
"Multihop attempted",
"RFS specific error",
"Not a data message",
"Value too large for defined data type",
"Name not unique on network",
"File descriptor in bad state",
"Remote address changed",
"Can not access a needed shared library",
"Accessing a corrupted shared library",
".lib section in a.out corrupted",
"Attempting to link in too many shared libraries",
"Cannot exec a shared library directly",
"Illegal byte sequence",
"Interrupted system call should be restarted",
"Streams pipe error",
"Too many users",
"Socket operation on non-socket",
"Destination address required",
"Message too long",
"Protocol wrong type for socket",
"Protocol not available",
"Protocol not supported",
"Socket type not supported",
"Operation not supported on transport endpoint",
"Protocol family not supported",
"Address family not supported by protocol",
"Address already in use",
"Cannot assign requested address",
"Network is down",
"Network is unreachable",
"Network dropped connection because of reset",
"Software caused connection abort",
"Connection reset by peer",
"No buffer space available",
"Transport endpoint is already connected",
"Transport endpoint is not connected",
"Cannot send after transport endpoint shutdown",
"Too many references: cannot splice",
"Connection timed out",
"Connection refused",
"Host is down",
"No route to host",
"Operation already in progress",
"Operation now in progress",
"Stale NFS file handle",
"Structure needs cleaning",
"Not a XENIX named type file",
"No XENIX semaphores available",
"Is a named type file",
"Remote I/O error",
"Quota exceeded",
"No medium found",
"Wrong medium type",
"Operation Canceled",
"Required key not available",
"Key has expired",
"Key has been revoked",
"Key was rejected by service",
"Owner died",
"State not recoverable"];

View File

@ -1,148 +0,0 @@
pub const CLONE_VM: usize = 0x100;
pub const CLONE_FS: usize = 0x200;
pub const CLONE_FILES: usize = 0x400;
pub const CLONE_SIGHAND: usize = 0x800;
pub const CLONE_VFORK: usize = 0x4000;
pub const CLONE_THREAD: usize = 0x10000;
pub const CLOCK_REALTIME: usize = 1;
pub const CLOCK_MONOTONIC: usize = 4;
pub const EVENT_NONE: usize = 0;
pub const EVENT_READ: usize = 1;
pub const EVENT_WRITE: usize = 2;
pub const F_DUPFD: usize = 0;
pub const F_GETFD: usize = 1;
pub const F_SETFD: usize = 2;
pub const F_GETFL: usize = 3;
pub const F_SETFL: usize = 4;
pub const FUTEX_WAIT: usize = 0;
pub const FUTEX_WAKE: usize = 1;
pub const FUTEX_REQUEUE: usize = 2;
pub const MAP_WRITE: usize = 1;
pub const MAP_WRITE_COMBINE: usize = 2;
pub const MODE_TYPE: u16 = 0xF000;
pub const MODE_DIR: u16 = 0x4000;
pub const MODE_FILE: u16 = 0x8000;
pub const MODE_SYMLINK: u16 = 0xA000;
pub const MODE_FIFO: u16 = 0x1000;
pub const MODE_CHR: u16 = 0x2000;
pub const MODE_PERM: u16 = 0x0FFF;
pub const MODE_SETUID: u16 = 0o4000;
pub const MODE_SETGID: u16 = 0o2000;
pub const O_RDONLY: usize = 0x0001_0000;
pub const O_WRONLY: usize = 0x0002_0000;
pub const O_RDWR: usize = 0x0003_0000;
pub const O_NONBLOCK: usize = 0x0004_0000;
pub const O_APPEND: usize = 0x0008_0000;
pub const O_SHLOCK: usize = 0x0010_0000;
pub const O_EXLOCK: usize = 0x0020_0000;
pub const O_ASYNC: usize = 0x0040_0000;
pub const O_FSYNC: usize = 0x0080_0000;
pub const O_CLOEXEC: usize = 0x0100_0000;
pub const O_CREAT: usize = 0x0200_0000;
pub const O_TRUNC: usize = 0x0400_0000;
pub const O_EXCL: usize = 0x0800_0000;
pub const O_DIRECTORY: usize = 0x1000_0000;
pub const O_STAT: usize = 0x2000_0000;
pub const O_SYMLINK: usize = 0x4000_0000;
pub const O_NOFOLLOW: usize = 0x8000_0000;
pub const O_ACCMODE: usize = O_RDONLY | O_WRONLY | O_RDWR;
pub const SEEK_SET: usize = 0;
pub const SEEK_CUR: usize = 1;
pub const SEEK_END: usize = 2;
pub const SIGHUP: usize = 1;
pub const SIGINT: usize = 2;
pub const SIGQUIT: usize = 3;
pub const SIGILL: usize = 4;
pub const SIGTRAP: usize = 5;
pub const SIGABRT: usize = 6;
pub const SIGBUS: usize = 7;
pub const SIGFPE: usize = 8;
pub const SIGKILL: usize = 9;
pub const SIGUSR1: usize = 10;
pub const SIGSEGV: usize = 11;
pub const SIGUSR2: usize = 12;
pub const SIGPIPE: usize = 13;
pub const SIGALRM: usize = 14;
pub const SIGTERM: usize = 15;
pub const SIGSTKFLT: usize= 16;
pub const SIGCHLD: usize = 17;
pub const SIGCONT: usize = 18;
pub const SIGSTOP: usize = 19;
pub const SIGTSTP: usize = 20;
pub const SIGTTIN: usize = 21;
pub const SIGTTOU: usize = 22;
pub const SIGURG: usize = 23;
pub const SIGXCPU: usize = 24;
pub const SIGXFSZ: usize = 25;
pub const SIGVTALRM: usize= 26;
pub const SIGPROF: usize = 27;
pub const SIGWINCH: usize = 28;
pub const SIGIO: usize = 29;
pub const SIGPWR: usize = 30;
pub const SIGSYS: usize = 31;
pub const SIG_DFL: usize = 0;
pub const SIG_IGN: usize = 1;
pub const SA_NOCLDSTOP: usize = 0x00000001;
pub const SA_NOCLDWAIT: usize = 0x00000002;
pub const SA_SIGINFO: usize = 0x00000004;
pub const SA_RESTORER: usize = 0x04000000;
pub const SA_ONSTACK: usize = 0x08000000;
pub const SA_RESTART: usize = 0x10000000;
pub const SA_NODEFER: usize = 0x40000000;
pub const SA_RESETHAND: usize = 0x80000000;
pub const WNOHANG: usize = 0x01;
pub const WUNTRACED: usize = 0x02;
pub const WCONTINUED: usize = 0x08;
/// Returns `true` if status indicates the child is stopped.
pub fn wifstopped(status: usize) -> bool {
(status & 0xff) == 0x7f
}
/// If wifstopped(status), returns the signal that stopped the child.
pub fn wstopsig(status: usize) -> usize {
(status >> 8) & 0xff
}
/// Returns `true` if status indicates the child continued after a stop.
pub fn wifcontinued(status: usize) -> bool {
status == 0xffff
}
/// Returns `true` if status indicates termination by a signal.
pub fn wifsignaled(status: usize) -> bool {
((status & 0x7f) + 1) as i8 >= 2
}
/// If wifsignaled(status), returns the terminating signal.
pub fn wtermsig(status: usize) -> usize {
status & 0x7f
}
/// Returns `true` if status indicates normal termination.
pub fn wifexited(status: usize) -> bool {
wtermsig(status) == 0
}
/// If wifexited(status), returns the exit status.
pub fn wexitstatus(status: usize) -> usize {
(status >> 8) & 0xff
}
/// Returns `true` if status indicates a core dump was created.
pub fn wcoredump(status: usize) -> bool {
(status & 0x80) != 0
}

View File

@ -1,33 +0,0 @@
pub use self::arch::*;
pub use self::call::*;
pub use self::data::*;
pub use self::error::*;
pub use self::flag::*;
pub use self::number::*;
#[cfg(target_arch = "arm")]
#[path="arch/arm.rs"]
mod arch;
#[cfg(target_arch = "x86")]
#[path="arch/x86.rs"]
mod arch;
#[cfg(target_arch = "x86_64")]
#[path="arch/x86_64.rs"]
mod arch;
/// Function definitions
pub mod call;
/// Complex structures that are used for some system calls
pub mod data;
/// All errors that can be generated by a system call
pub mod error;
/// Flags used as an argument to many system calls
pub mod flag;
/// Call numbers used by each system call
pub mod number;

View File

@ -1,73 +0,0 @@
pub const SYS_CLASS: usize = 0xF000_0000;
pub const SYS_CLASS_PATH: usize=0x1000_0000;
pub const SYS_CLASS_FILE: usize=0x2000_0000;
pub const SYS_ARG: usize = 0x0F00_0000;
pub const SYS_ARG_SLICE: usize =0x0100_0000;
pub const SYS_ARG_MSLICE: usize=0x0200_0000;
pub const SYS_ARG_PATH: usize = 0x0300_0000;
pub const SYS_RET: usize = 0x00F0_0000;
pub const SYS_RET_FILE: usize = 0x0010_0000;
pub const SYS_LINK: usize = SYS_CLASS_PATH | SYS_ARG_PATH | 9;
pub const SYS_OPEN: usize = SYS_CLASS_PATH | SYS_RET_FILE | 5;
pub const SYS_CHMOD: usize = SYS_CLASS_PATH | 15;
pub const SYS_RMDIR: usize = SYS_CLASS_PATH | 84;
pub const SYS_UNLINK: usize = SYS_CLASS_PATH | 10;
pub const SYS_CLOSE: usize = SYS_CLASS_FILE | 6;
pub const SYS_DUP: usize = SYS_CLASS_FILE | SYS_RET_FILE | 41;
pub const SYS_DUP2: usize = SYS_CLASS_FILE | SYS_RET_FILE | 63;
pub const SYS_READ: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 3;
pub const SYS_WRITE: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 4;
pub const SYS_LSEEK: usize = SYS_CLASS_FILE | 19;
pub const SYS_FCHMOD: usize = SYS_CLASS_FILE | 94;
pub const SYS_FCHOWN: usize = SYS_CLASS_FILE | 207;
pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55;
pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927;
pub const SYS_FEXEC: usize = SYS_CLASS_FILE | 11;
pub const SYS_FMAP: usize = SYS_CLASS_FILE | 90;
pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 91;
pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928;
pub const SYS_FRENAME: usize = SYS_CLASS_FILE | SYS_ARG_PATH | 38;
pub const SYS_FSTAT: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 28;
pub const SYS_FSTATVFS: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 100;
pub const SYS_FSYNC: usize = SYS_CLASS_FILE | 118;
pub const SYS_FTRUNCATE: usize =SYS_CLASS_FILE | 93;
pub const SYS_FUTIMENS: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 320;
pub const SYS_BRK: usize = 45;
pub const SYS_CHDIR: usize = 12;
pub const SYS_CLOCK_GETTIME: usize = 265;
pub const SYS_CLONE: usize = 120;
pub const SYS_EXIT: usize = 1;
pub const SYS_FUTEX: usize = 240;
pub const SYS_GETCWD: usize = 183;
pub const SYS_GETEGID: usize = 202;
pub const SYS_GETENS: usize = 951;
pub const SYS_GETEUID: usize = 201;
pub const SYS_GETGID: usize = 200;
pub const SYS_GETNS: usize = 950;
pub const SYS_GETPID: usize = 20;
pub const SYS_GETPGID: usize = 132;
pub const SYS_GETPPID: usize = 64;
pub const SYS_GETUID: usize = 199;
pub const SYS_IOPL: usize = 110;
pub const SYS_KILL: usize = 37;
pub const SYS_MKNS: usize = 984;
pub const SYS_NANOSLEEP: usize =162;
pub const SYS_PHYSALLOC: usize =945;
pub const SYS_PHYSFREE: usize = 946;
pub const SYS_PHYSMAP: usize = 947;
pub const SYS_PHYSUNMAP: usize =948;
pub const SYS_VIRTTOPHYS: usize=949;
pub const SYS_PIPE2: usize = 331;
pub const SYS_SETPGID: usize = 57;
pub const SYS_SETREGID: usize = 204;
pub const SYS_SETRENS: usize = 952;
pub const SYS_SETREUID: usize = 203;
pub const SYS_SIGACTION: usize =67;
pub const SYS_SIGRETURN: usize =119;
pub const SYS_WAITPID: usize = 7;
pub const SYS_YIELD: usize = 158;

View File

@ -1,84 +0,0 @@
use crate::ffi::CStr;
use crate::io;
use crate::mem;
use crate::sys_common::thread::start_thread;
use crate::sys::{cvt, syscall};
use crate::time::Duration;
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
pub struct Thread {
id: usize,
}
// Some platforms may have pthread_t as a pointer in which case we still want
// a thread to be Send/Sync
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}
impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
let p = box p;
let id = cvt(syscall::clone(syscall::CLONE_VM | syscall::CLONE_FS | syscall::CLONE_FILES))?;
if id == 0 {
start_thread(&*p as *const _ as *mut _);
let _ = syscall::exit(0);
panic!("thread failed to exit");
} else {
mem::forget(p);
Ok(Thread { id })
}
}
pub fn yield_now() {
let ret = syscall::sched_yield().expect("failed to sched_yield");
debug_assert_eq!(ret, 0);
}
pub fn set_name(_name: &CStr) {
}
pub fn sleep(dur: Duration) {
let mut secs = dur.as_secs();
let mut nsecs = dur.subsec_nanos() as i32;
// If we're awoken with a signal then the return value will be -1 and
// nanosleep will fill in `ts` with the remaining time.
while secs > 0 || nsecs > 0 {
let req = syscall::TimeSpec {
tv_sec: secs as i64,
tv_nsec: nsecs,
};
secs -= req.tv_sec as u64;
let mut rem = syscall::TimeSpec::default();
if syscall::nanosleep(&req, &mut rem).is_err() {
secs += rem.tv_sec as u64;
nsecs = rem.tv_nsec;
} else {
nsecs = 0;
}
}
}
pub fn join(self) {
let mut status = 0;
syscall::waitpid(self.id, &mut status, 0).unwrap();
}
pub fn id(&self) -> usize { self.id }
pub fn into_id(self) -> usize {
let id = self.id;
mem::forget(self);
id
}
}
pub mod guard {
pub type Guard = !;
pub unsafe fn current() -> Option<Guard> { None }
pub unsafe fn init() -> Option<Guard> { None }
}

View File

@ -1,61 +0,0 @@
#![allow(dead_code)] // not used on all platforms
use crate::collections::BTreeMap;
use crate::ptr;
use crate::sync::atomic::{AtomicUsize, Ordering};
pub type Key = usize;
type Dtor = unsafe extern fn(*mut u8);
static NEXT_KEY: AtomicUsize = AtomicUsize::new(0);
static mut KEYS: *mut BTreeMap<Key, Option<Dtor>> = ptr::null_mut();
#[thread_local]
static mut LOCALS: *mut BTreeMap<Key, *mut u8> = ptr::null_mut();
unsafe fn keys() -> &'static mut BTreeMap<Key, Option<Dtor>> {
if KEYS == ptr::null_mut() {
KEYS = Box::into_raw(Box::new(BTreeMap::new()));
}
&mut *KEYS
}
unsafe fn locals() -> &'static mut BTreeMap<Key, *mut u8> {
if LOCALS == ptr::null_mut() {
LOCALS = Box::into_raw(Box::new(BTreeMap::new()));
}
&mut *LOCALS
}
#[inline]
pub unsafe fn create(dtor: Option<Dtor>) -> Key {
let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst);
keys().insert(key, dtor);
key
}
#[inline]
pub unsafe fn get(key: Key) -> *mut u8 {
if let Some(&entry) = locals().get(&key) {
entry
} else {
ptr::null_mut()
}
}
#[inline]
pub unsafe fn set(key: Key, value: *mut u8) {
locals().insert(key, value);
}
#[inline]
pub unsafe fn destroy(key: Key) {
keys().remove(&key);
}
#[inline]
pub fn requires_synchronized_create() -> bool {
false
}

View File

@ -1,207 +0,0 @@
use crate::cmp::Ordering;
use crate::fmt;
use crate::sys::{cvt, syscall};
use crate::time::Duration;
use crate::convert::TryInto;
use core::hash::{Hash, Hasher};
const NSEC_PER_SEC: u64 = 1_000_000_000;
#[derive(Copy, Clone)]
struct Timespec {
t: syscall::TimeSpec,
}
impl Timespec {
fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
if self >= other {
Ok(if self.t.tv_nsec >= other.t.tv_nsec {
Duration::new((self.t.tv_sec - other.t.tv_sec) as u64,
(self.t.tv_nsec - other.t.tv_nsec) as u32)
} else {
Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64,
self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) -
other.t.tv_nsec as u32)
})
} else {
match other.sub_timespec(self) {
Ok(d) => Err(d),
Err(d) => Ok(d),
}
}
}
fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = other
.as_secs()
.try_into() // <- target type would be `i64`
.ok()
.and_then(|secs| self.t.tv_sec.checked_add(secs))?;
// Nano calculations can't overflow because nanos are <1B which fit
// in a u32.
let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
if nsec >= NSEC_PER_SEC as u32 {
nsec -= NSEC_PER_SEC as u32;
secs = secs.checked_add(1)?;
}
Some(Timespec {
t: syscall::TimeSpec {
tv_sec: secs,
tv_nsec: nsec as i32,
},
})
}
fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = other
.as_secs()
.try_into() // <- target type would be `i64`
.ok()
.and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
// Similar to above, nanos can't overflow.
let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
if nsec < 0 {
nsec += NSEC_PER_SEC as i32;
secs = secs.checked_sub(1)?;
}
Some(Timespec {
t: syscall::TimeSpec {
tv_sec: secs,
tv_nsec: nsec as i32,
},
})
}
}
impl PartialEq for Timespec {
fn eq(&self, other: &Timespec) -> bool {
self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
}
}
impl Eq for Timespec {}
impl PartialOrd for Timespec {
fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Timespec {
fn cmp(&self, other: &Timespec) -> Ordering {
let me = (self.t.tv_sec, self.t.tv_nsec);
let other = (other.t.tv_sec, other.t.tv_nsec);
me.cmp(&other)
}
}
impl Hash for Timespec {
fn hash<H : Hasher>(&self, state: &mut H) {
self.t.tv_sec.hash(state);
self.t.tv_nsec.hash(state);
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Instant {
t: Timespec,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SystemTime {
t: Timespec,
}
pub const UNIX_EPOCH: SystemTime = SystemTime {
t: Timespec {
t: syscall::TimeSpec {
tv_sec: 0,
tv_nsec: 0,
},
},
};
impl Instant {
pub fn now() -> Instant {
Instant { t: now(syscall::CLOCK_MONOTONIC) }
}
pub const fn zero() -> Instant {
Instant { t: Timespec { t: syscall::TimeSpec { tv_sec: 0, tv_nsec: 0 } } }
}
pub fn actually_monotonic() -> bool {
false
}
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.t.sub_timespec(&other.t).ok()
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
Some(Instant { t: self.t.checked_add_duration(other)? })
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
Some(Instant { t: self.t.checked_sub_duration(other)? })
}
}
impl fmt::Debug for Instant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Instant")
.field("tv_sec", &self.t.t.tv_sec)
.field("tv_nsec", &self.t.t.tv_nsec)
.finish()
}
}
impl SystemTime {
pub fn now() -> SystemTime {
SystemTime { t: now(syscall::CLOCK_REALTIME) }
}
pub fn sub_time(&self, other: &SystemTime)
-> Result<Duration, Duration> {
self.t.sub_timespec(&other.t)
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime { t: self.t.checked_add_duration(other)? })
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
}
}
impl From<syscall::TimeSpec> for SystemTime {
fn from(t: syscall::TimeSpec) -> SystemTime {
SystemTime { t: Timespec { t } }
}
}
impl fmt::Debug for SystemTime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SystemTime")
.field("tv_sec", &self.t.t.tv_sec)
.field("tv_nsec", &self.t.t.tv_nsec)
.finish()
}
}
pub type clock_t = usize;
fn now(clock: clock_t) -> Timespec {
let mut t = Timespec {
t: syscall::TimeSpec {
tv_sec: 0,
tv_nsec: 0,
}
};
cvt(syscall::clock_gettime(clock, &mut t.t)).unwrap();
t
}

View File

@ -56,7 +56,8 @@ impl DoubleEndedIterator for Args {
target_os = "haiku",
target_os = "l4re",
target_os = "fuchsia",
target_os = "hermit"))]
target_os = "hermit",
target_os = "redox"))]
mod imp {
use crate::os::unix::prelude::*;
use crate::ptr;

View File

@ -31,14 +31,16 @@ impl Condvar {
target_os = "ios",
target_os = "l4re",
target_os = "android",
target_os = "hermit"))]
target_os = "hermit",
target_os = "redox"))]
pub unsafe fn init(&mut self) {}
#[cfg(not(any(target_os = "macos",
target_os = "ios",
target_os = "l4re",
target_os = "android",
target_os = "hermit")))]
target_os = "hermit",
target_os = "redox")))]
pub unsafe fn init(&mut self) {
use crate::mem::MaybeUninit;
let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit();

View File

@ -162,3 +162,14 @@ pub mod os {
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "redox")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "redox";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}

View File

@ -10,7 +10,7 @@
// fallback implementation to use as well.
//
// Due to rust-lang/rust#18804, make sure this is not generic!
#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "hermit"))]
#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "hermit", target_os = "redox"))]
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
use crate::mem;
use crate::sys_common::thread_local::register_dtor_fallback;

View File

@ -176,7 +176,8 @@ impl FileDesc {
target_os = "fuchsia",
target_os = "l4re",
target_os = "linux",
target_os = "haiku")))]
target_os = "haiku",
target_os = "redox")))]
pub fn set_cloexec(&self) -> io::Result<()> {
unsafe {
cvt(libc::ioctl(self.fd, libc::FIOCLEX))?;
@ -189,7 +190,8 @@ impl FileDesc {
target_os = "fuchsia",
target_os = "l4re",
target_os = "linux",
target_os = "haiku"))]
target_os = "haiku",
target_os = "redox"))]
pub fn set_cloexec(&self) -> io::Result<()> {
unsafe {
let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;

View File

@ -33,7 +33,8 @@ use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t,
target_os = "emscripten",
target_os = "solaris",
target_os = "l4re",
target_os = "fuchsia")))]
target_os = "fuchsia",
target_os = "redox")))]
use libc::{readdir_r as readdir64_r};
pub use crate::sys_common::fs::remove_dir_all;
@ -69,7 +70,7 @@ pub struct DirEntry {
// on Solaris and Fuchsia because a) it uses a zero-length
// array to store the name, b) its lifetime between readdir
// calls is not guaranteed.
#[cfg(any(target_os = "solaris", target_os = "fuchsia"))]
#[cfg(any(target_os = "solaris", target_os = "fuchsia", target_os = "redox"))]
name: Box<[u8]>
}
@ -216,7 +217,7 @@ impl fmt::Debug for ReadDir {
impl Iterator for ReadDir {
type Item = io::Result<DirEntry>;
#[cfg(any(target_os = "solaris", target_os = "fuchsia"))]
#[cfg(any(target_os = "solaris", target_os = "fuchsia", target_os = "redox"))]
fn next(&mut self) -> Option<io::Result<DirEntry>> {
use crate::slice;
@ -253,7 +254,7 @@ impl Iterator for ReadDir {
}
}
#[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))]
#[cfg(not(any(target_os = "solaris", target_os = "fuchsia", target_os = "redox")))]
fn next(&mut self) -> Option<io::Result<DirEntry>> {
if self.end_of_stream {
return None;
@ -346,7 +347,8 @@ impl DirEntry {
target_os = "haiku",
target_os = "l4re",
target_os = "fuchsia",
target_os = "hermit"))]
target_os = "hermit",
target_os = "redox"))]
pub fn ino(&self) -> u64 {
self.entry.d_ino as u64
}
@ -384,7 +386,8 @@ impl DirEntry {
}
}
#[cfg(any(target_os = "solaris",
target_os = "fuchsia"))]
target_os = "fuchsia",
target_os = "redox"))]
fn name_bytes(&self) -> &[u8] {
&*self.name
}

View File

@ -17,6 +17,7 @@ use crate::io::ErrorKind;
#[cfg(all(not(rustdoc), target_os = "fuchsia"))] pub use crate::os::fuchsia as platform;
#[cfg(all(not(rustdoc), target_os = "l4re"))] pub use crate::os::linux as platform;
#[cfg(all(not(rustdoc), target_os = "hermit"))] pub use crate::os::hermit as platform;
#[cfg(all(not(rustdoc), target_os = "redox"))] pub use crate::os::redox as platform;
pub use self::rand::hashmap_random_keys;
pub use libc::strlen;

View File

@ -25,6 +25,13 @@ use libc::{c_int, c_char, c_void};
const TMPBUF_SZ: usize = 128;
cfg_if::cfg_if! {
if #[cfg(target_os = "redox")] {
const PATH_SEPARATOR: u8 = b';';
} else {
const PATH_SEPARATOR: u8 = b':';
}
}
extern {
#[cfg(not(target_os = "dragonfly"))]
@ -37,6 +44,7 @@ extern {
target_os = "openbsd",
target_os = "android",
target_os = "hermit",
target_os = "redox",
target_env = "newlib"),
link_name = "__errno")]
#[cfg_attr(target_os = "solaris", link_name = "___errno")]
@ -155,10 +163,10 @@ pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
fn bytes_to_path(b: &[u8]) -> PathBuf {
PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
}
fn is_colon(b: &u8) -> bool { *b == b':' }
fn is_separator(b: &u8) -> bool { *b == PATH_SEPARATOR }
let unparsed = unparsed.as_bytes();
SplitPaths {
iter: unparsed.split(is_colon as fn(&u8) -> bool)
iter: unparsed.split(is_separator as fn(&u8) -> bool)
.map(bytes_to_path as fn(&[u8]) -> PathBuf)
}
}
@ -176,12 +184,11 @@ pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
where I: Iterator<Item=T>, T: AsRef<OsStr>
{
let mut joined = Vec::new();
let sep = b':';
for (i, path) in paths.enumerate() {
let path = path.as_ref().as_bytes();
if i > 0 { joined.push(sep) }
if path.contains(&sep) {
if i > 0 { joined.push(PATH_SEPARATOR) }
if path.contains(&PATH_SEPARATOR) {
return Err(JoinPathsError)
}
joined.extend_from_slice(path);
@ -191,7 +198,7 @@ pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
impl fmt::Display for JoinPathsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
"path segment contains separator `:`".fmt(f)
write!(f, "path segment contains separator `{}`", PATH_SEPARATOR)
}
}
@ -382,6 +389,11 @@ pub fn current_exe() -> io::Result<PathBuf> {
}
}
#[cfg(target_os = "redox")]
pub fn current_exe() -> io::Result<PathBuf> {
crate::fs::read_to_string("sys:exe").map(PathBuf::from)
}
#[cfg(any(target_os = "fuchsia", target_os = "l4re", target_os = "hermit"))]
pub fn current_exe() -> io::Result<PathBuf> {
use crate::io::ErrorKind;
@ -511,11 +523,13 @@ pub fn home_dir() -> Option<PathBuf> {
#[cfg(any(target_os = "android",
target_os = "ios",
target_os = "emscripten"))]
target_os = "emscripten",
target_os = "redox"))]
unsafe fn fallback() -> Option<OsString> { None }
#[cfg(not(any(target_os = "android",
target_os = "ios",
target_os = "emscripten")))]
target_os = "emscripten",
target_os = "redox")))]
unsafe fn fallback() -> Option<OsString> {
let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
n if n < 0 => 512 as usize,

View File

@ -26,7 +26,8 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd")) &&
target_os = "openbsd",
target_os = "redox")) &&
!INVALID.load(Ordering::SeqCst)
{

View File

@ -12,6 +12,14 @@ use crate::collections::BTreeMap;
use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};
cfg_if::cfg_if! {
if #[cfg(target_os = "redox")] {
const DEV_NULL: &'static str = "null:\0";
} else {
const DEV_NULL: &'static str = "/dev/null\0";
}
}
////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////
@ -298,7 +306,7 @@ impl Stdio {
opts.read(readable);
opts.write(!readable);
let path = unsafe {
CStr::from_ptr("/dev/null\0".as_ptr() as *const _)
CStr::from_ptr(DEV_NULL.as_ptr() as *const _)
};
let fd = File::open_c(&path, &opts)?;
Ok((ChildStdio::Owned(fd.into_fd()), None))

View File

@ -183,14 +183,17 @@ impl Command {
cvt(libc::setgid(u as gid_t))?;
}
if let Some(u) = self.get_uid() {
// When dropping privileges from root, the `setgroups` call
// will remove any extraneous groups. If we don't call this,
// then even though our uid has dropped, we may still have
// groups that enable us to do super-user things. This will
// fail if we aren't root, so don't bother checking the
// return value, this is just done as an optimistic
// privilege dropping function.
let _ = libc::setgroups(0, ptr::null());
//FIXME: Redox kernel does not support setgroups yet
if cfg!(not(target_os = "redox")) {
// When dropping privileges from root, the `setgroups` call
// will remove any extraneous groups. If we don't call this,
// then even though our uid has dropped, we may still have
// groups that enable us to do super-user things. This will
// fail if we aren't root, so don't bother checking the
// return value, this is just done as an optimistic
// privilege dropping function.
let _ = libc::setgroups(0, ptr::null());
}
cvt(libc::setuid(u as uid_t))?;
}

View File

@ -15,7 +15,8 @@ pub fn hashmap_random_keys() -> (u64, u64) {
not(target_os = "ios"),
not(target_os = "openbsd"),
not(target_os = "freebsd"),
not(target_os = "fuchsia")))]
not(target_os = "fuchsia"),
not(target_os = "redox")))]
mod imp {
use crate::fs::File;
use crate::io::Read;
@ -174,3 +175,15 @@ mod imp {
unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
}
}
#[cfg(target_os = "redox")]
mod imp {
use crate::fs::File;
use crate::io::Read;
pub fn fill_bytes(v: &mut [u8]) {
// Open rand:, read from it, and close it again.
let mut file = File::open("rand:").expect("failed to open rand:");
file.read_exact(v).expect("failed to read rand:")
}
}

View File

@ -140,7 +140,8 @@ impl Thread {
target_os = "haiku",
target_os = "l4re",
target_os = "emscripten",
target_os = "hermit"))]
target_os = "hermit",
target_os = "redox"))]
pub fn set_name(_name: &CStr) {
// Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name.
}

View File

@ -68,7 +68,6 @@ pub mod fs;
cfg_if::cfg_if! {
if #[cfg(any(target_os = "cloudabi",
target_os = "l4re",
target_os = "redox",
all(target_arch = "wasm32", not(target_os = "emscripten")),
all(target_vendor = "fortanix", target_env = "sgx")))] {
pub use crate::sys::net;

View File

@ -40,7 +40,7 @@ fn main() {
} else if target.contains("haiku") {
println!("cargo:rustc-link-lib=gcc_s");
} else if target.contains("redox") {
println!("cargo:rustc-link-lib=gcc");
// redox is handled in lib.rs
} else if target.contains("cloudabi") {
println!("cargo:rustc-link-lib=unwind");
}

View File

@ -24,3 +24,8 @@ cfg_if::cfg_if! {
#[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern {}
#[cfg(target_os = "redox")]
#[link(name = "gcc_eh", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern {}

View File

@ -46,6 +46,7 @@ static TARGETS: &[&str] = &[
"aarch64-unknown-cloudabi",
"aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-musl",
"aarch64-unknown-redox",
"arm-linux-androideabi",
"arm-unknown-linux-gnueabi",
"arm-unknown-linux-gnueabihf",