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:
commit
ad7c55e1fc
@ -1,5 +0,0 @@
|
||||
# `n16`
|
||||
|
||||
This feature is internal to the Rust compiler and is not intended for general use.
|
||||
|
||||
------------------------
|
@ -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();
|
||||
|
20
src/librustc_target/spec/aarch64_unknown_redox.rs
Normal file
20
src/librustc_target/spec/aarch64_unknown_redox.rs
Normal 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,
|
||||
})
|
||||
}
|
@ -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),
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
383
src/libstd/os/redox/fs.rs
Normal 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
|
||||
}
|
||||
}
|
6
src/libstd/os/redox/mod.rs
Normal file
6
src/libstd/os/redox/mod.rs
Normal file
@ -0,0 +1,6 @@
|
||||
//! Redox-specific definitions
|
||||
|
||||
#![stable(feature = "raw_ext", since = "1.1.0")]
|
||||
|
||||
pub mod raw;
|
||||
pub mod fs;
|
67
src/libstd/os/redox/raw.rs
Normal file
67
src/libstd/os/redox/raw.rs
Normal 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],
|
||||
}
|
@ -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':')
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
@ -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 {}
|
@ -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 = "";
|
||||
}
|
@ -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::*;
|
@ -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
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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};
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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;
|
@ -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);
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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};
|
@ -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();
|
||||
}
|
@ -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 {}
|
@ -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>
|
||||
}
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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))
|
||||
}
|
@ -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,
|
||||
}
|
@ -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 }
|
||||
}
|
@ -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 }
|
||||
}
|
@ -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
|
||||
}
|
@ -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 = '/';
|
@ -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(|_| ());
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
@ -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)))
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
pub fn hashmap_random_keys() -> (u64, u64) {
|
||||
(0, 0)
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
||||
}
|
@ -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()
|
||||
}
|
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
@ -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) }
|
||||
}
|
@ -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]
|
||||
}
|
||||
}
|
||||
}
|
@ -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"];
|
@ -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
|
||||
}
|
@ -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;
|
@ -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;
|
@ -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 }
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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 = "";
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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))?;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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))?;
|
||||
}
|
||||
|
@ -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:")
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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 {}
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user