2014-11-24 16:21:39 -08:00
|
|
|
//! Implementation of `std::os` functionality for unix systems
|
|
|
|
|
|
2015-03-09 20:04:35 -07:00
|
|
|
#![allow(unused_imports)] // lots of cfg code here
|
|
|
|
|
|
Refactor weak symbols in std::sys::unix
This makes a few changes to the weak symbol macros in `sys::unix`:
- `dlsym!` is added to keep the functionality for runtime `dlsym`
lookups, like for `__pthread_get_minstack@GLIBC_PRIVATE` that we don't
want to show up in ELF symbol tables.
- `weak!` now uses `#[linkage = "extern_weak"]` symbols, so its runtime
behavior is just a simple null check. This is also used by `syscall!`.
- On non-ELF targets (macos/ios) where that linkage is not known to
behave, `weak!` is just an alias to `dlsym!` for the old behavior.
- `raw_syscall!` is added to always call `libc::syscall` on linux and
android, for cases like `clone3` that have no known libc wrapper.
The new `weak!` linkage does mean that you'll get versioned symbols if
you build with a newer glibc, like `WEAK DEFAULT UND statx@GLIBC_2.28`.
This might seem problematic, but old non-weak symbols can tie the build
to new versions too, like `dlsym@GLIBC_2.34` from their recent library
unification. If you build with an old glibc like `dist-x86_64-linux`
does, you'll still get unversioned `WEAK DEFAULT UND statx`, which may
be resolved based on the runtime glibc.
I also found a few functions that don't need to be weak anymore:
- Android can directly use `ftruncate64`, `pread64`, and `pwrite64`, as
these were added in API 12, and our baseline is API 14.
- Linux can directly use `splice`, added way back in glibc 2.5 and
similarly old musl. Android only added it in API 21 though.
2021-11-12 12:58:38 -08:00
|
|
|
#[cfg(test)]
|
2020-08-27 13:45:01 +00:00
|
|
|
mod tests;
|
|
|
|
|
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::os::unix::prelude::*;
|
|
|
|
|
|
|
|
|
|
use crate::error::Error as StdError;
|
2019-12-24 17:38:22 -05:00
|
|
|
use crate::ffi::{CStr, CString, OsStr, OsString};
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::fmt;
|
|
|
|
|
use crate::io;
|
|
|
|
|
use crate::iter;
|
|
|
|
|
use crate::mem;
|
|
|
|
|
use crate::path::{self, PathBuf};
|
|
|
|
|
use crate::ptr;
|
|
|
|
|
use crate::slice;
|
|
|
|
|
use crate::str;
|
2022-08-15 14:33:12 +02:00
|
|
|
use crate::sync::{PoisonError, RwLock};
|
2022-09-22 04:40:43 -04:00
|
|
|
use crate::sys::common::small_c_string::{run_path_with_cstr, run_with_cstr};
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::sys::cvt;
|
|
|
|
|
use crate::sys::fd;
|
2021-05-14 03:54:46 +02:00
|
|
|
use crate::sys::memchr;
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::vec;
|
|
|
|
|
|
2021-07-05 20:28:10 -07:00
|
|
|
#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
|
|
|
|
|
use crate::sys::weak::weak;
|
|
|
|
|
|
2019-12-24 17:38:22 -05:00
|
|
|
use libc::{c_char, c_int, c_void};
|
2014-09-30 17:03:56 -07:00
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
const TMPBUF_SZ: usize = 128;
|
2014-11-24 16:21:39 -08:00
|
|
|
|
2019-08-06 19:32:39 -06:00
|
|
|
cfg_if::cfg_if! {
|
2019-04-07 08:39:54 -06:00
|
|
|
if #[cfg(target_os = "redox")] {
|
|
|
|
|
const PATH_SEPARATOR: u8 = b';';
|
|
|
|
|
} else {
|
|
|
|
|
const PATH_SEPARATOR: u8 = b':';
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-07-11 21:43:53 -07:00
|
|
|
|
2019-12-24 17:38:22 -05:00
|
|
|
extern "C" {
|
2020-10-07 20:38:25 +02:00
|
|
|
#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))]
|
2019-12-24 17:38:22 -05:00
|
|
|
#[cfg_attr(
|
|
|
|
|
any(
|
|
|
|
|
target_os = "linux",
|
|
|
|
|
target_os = "emscripten",
|
|
|
|
|
target_os = "fuchsia",
|
|
|
|
|
target_os = "l4re"
|
|
|
|
|
),
|
|
|
|
|
link_name = "__errno_location"
|
|
|
|
|
)]
|
|
|
|
|
#[cfg_attr(
|
|
|
|
|
any(
|
|
|
|
|
target_os = "netbsd",
|
|
|
|
|
target_os = "openbsd",
|
|
|
|
|
target_os = "android",
|
|
|
|
|
target_os = "redox",
|
|
|
|
|
target_env = "newlib"
|
|
|
|
|
),
|
|
|
|
|
link_name = "__errno"
|
|
|
|
|
)]
|
2020-04-13 23:37:22 +00:00
|
|
|
#[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")]
|
2023-01-10 10:44:05 +01:00
|
|
|
#[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")]
|
2019-12-24 17:38:22 -05:00
|
|
|
#[cfg_attr(
|
2022-03-23 16:05:01 +00:00
|
|
|
any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "watchos"),
|
2019-12-24 17:38:22 -05:00
|
|
|
link_name = "__error"
|
|
|
|
|
)]
|
2016-09-24 23:38:56 -05:00
|
|
|
#[cfg_attr(target_os = "haiku", link_name = "_errnop")]
|
2016-07-11 21:43:53 -07:00
|
|
|
fn errno_location() -> *mut c_int;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-30 17:03:56 -07:00
|
|
|
/// Returns the platform-specific value of errno
|
2020-10-07 20:38:25 +02:00
|
|
|
#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))]
|
2015-01-27 12:20:58 -08:00
|
|
|
pub fn errno() -> i32 {
|
2019-12-24 17:38:22 -05:00
|
|
|
unsafe { (*errno_location()) as i32 }
|
2016-07-11 21:43:53 -07:00
|
|
|
}
|
2014-09-30 17:03:56 -07:00
|
|
|
|
2016-07-11 21:43:53 -07:00
|
|
|
/// Sets the platform-specific value of errno
|
2022-01-11 14:09:52 -05:00
|
|
|
#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall!
|
2020-07-22 16:38:58 -07:00
|
|
|
#[allow(dead_code)] // but not all target cfgs actually end up using it
|
2016-07-11 21:43:53 -07:00
|
|
|
pub fn set_errno(e: i32) {
|
2019-12-24 17:38:22 -05:00
|
|
|
unsafe { *errno_location() = e as c_int }
|
2014-09-30 17:03:56 -07:00
|
|
|
}
|
|
|
|
|
|
2020-10-07 20:38:25 +02:00
|
|
|
#[cfg(target_os = "vxworks")]
|
|
|
|
|
pub fn errno() -> i32 {
|
|
|
|
|
unsafe { libc::errnoGet() }
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-02 19:06:16 +02:00
|
|
|
#[cfg(target_os = "dragonfly")]
|
|
|
|
|
pub fn errno() -> i32 {
|
2019-12-24 17:38:22 -05:00
|
|
|
extern "C" {
|
2016-04-02 19:06:16 +02:00
|
|
|
#[thread_local]
|
|
|
|
|
static errno: c_int;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-06 19:31:48 +01:00
|
|
|
unsafe { errno as i32 }
|
2016-04-02 19:06:16 +02:00
|
|
|
}
|
|
|
|
|
|
2018-12-21 15:53:37 +02:00
|
|
|
#[cfg(target_os = "dragonfly")]
|
2021-12-02 16:16:27 -06:00
|
|
|
#[allow(dead_code)]
|
2018-12-21 15:53:37 +02:00
|
|
|
pub fn set_errno(e: i32) {
|
2019-12-24 17:38:22 -05:00
|
|
|
extern "C" {
|
2018-12-21 15:53:37 +02:00
|
|
|
#[thread_local]
|
|
|
|
|
static mut errno: c_int;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
errno = e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-13 10:21:32 -04:00
|
|
|
/// Gets a detailed string description for the given error number.
|
2014-09-30 17:03:56 -07:00
|
|
|
pub fn error_string(errno: i32) -> String {
|
2019-12-24 17:38:22 -05:00
|
|
|
extern "C" {
|
2022-11-10 10:06:34 +00:00
|
|
|
#[cfg_attr(
|
|
|
|
|
all(any(target_os = "linux", target_env = "newlib"), not(target_env = "ohos")),
|
|
|
|
|
link_name = "__xpg_strerror_r"
|
|
|
|
|
)]
|
2019-12-24 17:38:22 -05:00
|
|
|
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) -> c_int;
|
2014-09-30 17:03:56 -07:00
|
|
|
}
|
|
|
|
|
|
2015-01-01 17:40:24 +13:00
|
|
|
let mut buf = [0 as c_char; TMPBUF_SZ];
|
2014-09-30 17:03:56 -07:00
|
|
|
|
|
|
|
|
let p = buf.as_mut_ptr();
|
|
|
|
|
unsafe {
|
2016-10-08 15:48:28 +02:00
|
|
|
if strerror_r(errno as c_int, p, buf.len()) < 0 {
|
2014-09-30 17:03:56 -07:00
|
|
|
panic!("strerror_r failure");
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-25 13:28:35 -08:00
|
|
|
let p = p as *const _;
|
2022-07-22 08:50:31 -07:00
|
|
|
// We can't always expect a UTF-8 environment. When we don't get that luxury,
|
|
|
|
|
// it's better to give a low-quality error message than none at all.
|
|
|
|
|
String::from_utf8_lossy(CStr::from_ptr(p).to_bytes()).into()
|
2014-09-30 17:03:56 -07:00
|
|
|
}
|
|
|
|
|
}
|
2014-10-10 10:11:49 -07:00
|
|
|
|
2021-07-29 20:18:22 +03:00
|
|
|
#[cfg(target_os = "espidf")]
|
|
|
|
|
pub fn getcwd() -> io::Result<PathBuf> {
|
|
|
|
|
Ok(PathBuf::from("/"))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(not(target_os = "espidf"))]
|
2015-02-23 10:59:17 -08:00
|
|
|
pub fn getcwd() -> io::Result<PathBuf> {
|
2015-08-26 21:27:32 +09:00
|
|
|
let mut buf = Vec::with_capacity(512);
|
2015-07-10 12:33:10 +02:00
|
|
|
loop {
|
2015-07-08 21:36:46 +02:00
|
|
|
unsafe {
|
2015-07-09 15:03:10 +02:00
|
|
|
let ptr = buf.as_mut_ptr() as *mut libc::c_char;
|
2016-10-08 15:48:28 +02:00
|
|
|
if !libc::getcwd(ptr, buf.capacity()).is_null() {
|
2015-07-09 15:03:10 +02:00
|
|
|
let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len();
|
|
|
|
|
buf.set_len(len);
|
2015-07-10 12:33:10 +02:00
|
|
|
buf.shrink_to_fit();
|
|
|
|
|
return Ok(PathBuf::from(OsString::from_vec(buf)));
|
2015-07-08 21:36:46 +02:00
|
|
|
} else {
|
|
|
|
|
let error = io::Error::last_os_error();
|
2015-07-10 12:33:10 +02:00
|
|
|
if error.raw_os_error() != Some(libc::ERANGE) {
|
|
|
|
|
return Err(error);
|
2015-07-08 21:36:46 +02:00
|
|
|
}
|
2015-07-10 12:33:10 +02:00
|
|
|
}
|
2015-08-26 21:27:32 +09:00
|
|
|
|
|
|
|
|
// Trigger the internal buffer resizing logic of `Vec` by requiring
|
|
|
|
|
// more space than the current capacity.
|
|
|
|
|
let cap = buf.capacity();
|
|
|
|
|
buf.set_len(cap);
|
|
|
|
|
buf.reserve(1);
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
2015-07-10 12:33:10 +02:00
|
|
|
}
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
|
2021-07-29 20:18:22 +03:00
|
|
|
#[cfg(target_os = "espidf")]
|
|
|
|
|
pub fn chdir(p: &path::Path) -> io::Result<()> {
|
|
|
|
|
super::unsupported::unsupported()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(not(target_os = "espidf"))]
|
2015-02-23 10:59:17 -08:00
|
|
|
pub fn chdir(p: &path::Path) -> io::Result<()> {
|
2022-09-22 04:40:43 -04:00
|
|
|
let result = run_path_with_cstr(p, |p| unsafe { Ok(libc::chdir(p.as_ptr())) })?;
|
|
|
|
|
if result == 0 { Ok(()) } else { Err(io::Error::last_os_error()) }
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct SplitPaths<'a> {
|
2019-12-24 17:38:22 -05:00
|
|
|
iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>, fn(&'a [u8]) -> PathBuf>,
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
|
|
|
|
|
2019-03-01 09:34:11 +01:00
|
|
|
pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
|
2015-07-09 15:03:10 +02:00
|
|
|
fn bytes_to_path(b: &[u8]) -> PathBuf {
|
|
|
|
|
PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
|
|
|
|
|
}
|
2019-12-24 17:38:22 -05:00
|
|
|
fn is_separator(b: &u8) -> bool {
|
|
|
|
|
*b == PATH_SEPARATOR
|
|
|
|
|
}
|
2015-02-06 09:42:57 -08:00
|
|
|
let unparsed = unparsed.as_bytes();
|
2015-01-27 12:20:58 -08:00
|
|
|
SplitPaths {
|
2019-12-24 17:38:22 -05:00
|
|
|
iter: unparsed
|
|
|
|
|
.split(is_separator as fn(&u8) -> bool)
|
|
|
|
|
.map(bytes_to_path as fn(&[u8]) -> PathBuf),
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
impl<'a> Iterator for SplitPaths<'a> {
|
2015-02-23 10:59:17 -08:00
|
|
|
type Item = PathBuf;
|
2019-12-24 17:38:22 -05:00
|
|
|
fn next(&mut self) -> Option<PathBuf> {
|
|
|
|
|
self.iter.next()
|
|
|
|
|
}
|
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
|
|
|
self.iter.size_hint()
|
|
|
|
|
}
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct JoinPathsError;
|
|
|
|
|
|
|
|
|
|
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
|
2019-12-24 17:38:22 -05:00
|
|
|
where
|
|
|
|
|
I: Iterator<Item = T>,
|
|
|
|
|
T: AsRef<OsStr>,
|
2015-01-27 12:20:58 -08:00
|
|
|
{
|
2014-11-24 16:21:39 -08:00
|
|
|
let mut joined = Vec::new();
|
|
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
for (i, path) in paths.enumerate() {
|
2015-03-30 11:00:05 -07:00
|
|
|
let path = path.as_ref().as_bytes();
|
2019-12-24 17:38:22 -05:00
|
|
|
if i > 0 {
|
|
|
|
|
joined.push(PATH_SEPARATOR)
|
|
|
|
|
}
|
2019-04-07 08:39:54 -06:00
|
|
|
if path.contains(&PATH_SEPARATOR) {
|
2019-12-24 17:38:22 -05:00
|
|
|
return Err(JoinPathsError);
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
2015-12-02 17:31:49 -08:00
|
|
|
joined.extend_from_slice(path);
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
2015-01-27 12:20:58 -08:00
|
|
|
Ok(OsStringExt::from_vec(joined))
|
|
|
|
|
}
|
2014-11-24 16:21:39 -08:00
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
impl fmt::Display for JoinPathsError {
|
2019-03-01 09:34:11 +01:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2021-04-13 14:20:49 -07:00
|
|
|
write!(f, "path segment contains separator `{}`", char::from(PATH_SEPARATOR))
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl StdError for JoinPathsError {
|
2019-11-30 20:01:48 -08:00
|
|
|
#[allow(deprecated)]
|
2019-12-24 17:38:22 -05:00
|
|
|
fn description(&self) -> &str {
|
|
|
|
|
"failed to join paths"
|
|
|
|
|
}
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
|
2016-12-06 19:31:48 +01:00
|
|
|
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
2015-02-25 14:15:24 +05:30
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
2014-11-24 16:21:39 -08:00
|
|
|
unsafe {
|
2019-12-24 17:38:22 -05:00
|
|
|
let mut mib = [
|
|
|
|
|
libc::CTL_KERN as c_int,
|
|
|
|
|
libc::KERN_PROC as c_int,
|
|
|
|
|
libc::KERN_PROC_PATHNAME as c_int,
|
|
|
|
|
-1 as c_int,
|
|
|
|
|
];
|
2016-10-08 15:48:28 +02:00
|
|
|
let mut sz = 0;
|
2019-12-24 17:38:22 -05:00
|
|
|
cvt(libc::sysctl(
|
|
|
|
|
mib.as_mut_ptr(),
|
|
|
|
|
mib.len() as libc::c_uint,
|
|
|
|
|
ptr::null_mut(),
|
|
|
|
|
&mut sz,
|
|
|
|
|
ptr::null_mut(),
|
|
|
|
|
0,
|
|
|
|
|
))?;
|
2015-12-02 10:31:29 -08:00
|
|
|
if sz == 0 {
|
2019-12-24 17:38:22 -05:00
|
|
|
return Err(io::Error::last_os_error());
|
2015-12-02 10:31:29 -08:00
|
|
|
}
|
2016-10-08 15:48:28 +02:00
|
|
|
let mut v: Vec<u8> = Vec::with_capacity(sz);
|
2019-12-24 17:38:22 -05:00
|
|
|
cvt(libc::sysctl(
|
|
|
|
|
mib.as_mut_ptr(),
|
|
|
|
|
mib.len() as libc::c_uint,
|
|
|
|
|
v.as_mut_ptr() as *mut libc::c_void,
|
|
|
|
|
&mut sz,
|
|
|
|
|
ptr::null_mut(),
|
|
|
|
|
0,
|
|
|
|
|
))?;
|
2015-12-02 10:31:29 -08:00
|
|
|
if sz == 0 {
|
|
|
|
|
return Err(io::Error::last_os_error());
|
|
|
|
|
}
|
2016-10-08 15:48:28 +02:00
|
|
|
v.set_len(sz - 1); // chop off trailing NUL
|
2015-03-25 08:42:15 +01:00
|
|
|
Ok(PathBuf::from(OsString::from_vec(v)))
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-20 17:39:52 +02:00
|
|
|
#[cfg(target_os = "netbsd")]
|
|
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
2017-11-29 11:31:09 -06:00
|
|
|
fn sysctl() -> io::Result<PathBuf> {
|
|
|
|
|
unsafe {
|
|
|
|
|
let mib = [libc::CTL_KERN, libc::KERN_PROC_ARGS, -1, libc::KERN_PROC_PATHNAME];
|
|
|
|
|
let mut path_len: usize = 0;
|
2019-12-24 17:38:22 -05:00
|
|
|
cvt(libc::sysctl(
|
|
|
|
|
mib.as_ptr(),
|
|
|
|
|
mib.len() as libc::c_uint,
|
|
|
|
|
ptr::null_mut(),
|
|
|
|
|
&mut path_len,
|
|
|
|
|
ptr::null(),
|
|
|
|
|
0,
|
|
|
|
|
))?;
|
2017-11-29 11:31:09 -06:00
|
|
|
if path_len <= 1 {
|
2021-08-08 01:04:33 -07:00
|
|
|
return Err(io::const_io_error!(
|
2021-06-15 14:27:31 +02:00
|
|
|
io::ErrorKind::Uncategorized,
|
2021-08-08 01:04:33 -07:00
|
|
|
"KERN_PROC_PATHNAME sysctl returned zero-length string",
|
2019-12-24 17:38:22 -05:00
|
|
|
));
|
2017-11-29 11:31:09 -06:00
|
|
|
}
|
|
|
|
|
let mut path: Vec<u8> = Vec::with_capacity(path_len);
|
2019-12-24 17:38:22 -05:00
|
|
|
cvt(libc::sysctl(
|
|
|
|
|
mib.as_ptr(),
|
|
|
|
|
mib.len() as libc::c_uint,
|
|
|
|
|
path.as_ptr() as *mut libc::c_void,
|
|
|
|
|
&mut path_len,
|
|
|
|
|
ptr::null(),
|
|
|
|
|
0,
|
|
|
|
|
))?;
|
2017-11-29 11:31:09 -06:00
|
|
|
path.set_len(path_len - 1); // chop off NUL
|
|
|
|
|
Ok(PathBuf::from(OsString::from_vec(path)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fn procfs() -> io::Result<PathBuf> {
|
|
|
|
|
let curproc_exe = path::Path::new("/proc/curproc/exe");
|
|
|
|
|
if curproc_exe.is_file() {
|
2019-02-11 04:23:21 +09:00
|
|
|
return crate::fs::read_link(curproc_exe);
|
2017-11-29 11:31:09 -06:00
|
|
|
}
|
2021-08-08 01:04:33 -07:00
|
|
|
Err(io::const_io_error!(
|
2021-06-15 14:27:31 +02:00
|
|
|
io::ErrorKind::Uncategorized,
|
2021-08-08 01:04:33 -07:00
|
|
|
"/proc/curproc/exe doesn't point to regular file.",
|
2019-12-24 17:38:22 -05:00
|
|
|
))
|
2017-11-29 11:31:09 -06:00
|
|
|
}
|
|
|
|
|
sysctl().or_else(|_| procfs())
|
2015-09-20 17:39:52 +02:00
|
|
|
}
|
|
|
|
|
|
2019-05-13 09:13:07 +02:00
|
|
|
#[cfg(target_os = "openbsd")]
|
2015-02-23 10:59:17 -08:00
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
2015-01-29 08:19:28 +01:00
|
|
|
unsafe {
|
2019-12-24 17:38:22 -05:00
|
|
|
let mut mib = [libc::CTL_KERN, libc::KERN_PROC_ARGS, libc::getpid(), libc::KERN_PROC_ARGV];
|
2015-12-02 10:31:29 -08:00
|
|
|
let mib = mib.as_mut_ptr();
|
|
|
|
|
let mut argv_len = 0;
|
2019-12-24 17:38:22 -05:00
|
|
|
cvt(libc::sysctl(mib, 4, ptr::null_mut(), &mut argv_len, ptr::null_mut(), 0))?;
|
2015-12-02 10:31:29 -08:00
|
|
|
let mut argv = Vec::<*const libc::c_char>::with_capacity(argv_len as usize);
|
2019-12-24 17:38:22 -05:00
|
|
|
cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _, &mut argv_len, ptr::null_mut(), 0))?;
|
2015-12-02 10:31:29 -08:00
|
|
|
argv.set_len(argv_len as usize);
|
|
|
|
|
if argv[0].is_null() {
|
2021-08-08 01:04:33 -07:00
|
|
|
return Err(io::const_io_error!(
|
2021-06-15 14:27:31 +02:00
|
|
|
io::ErrorKind::Uncategorized,
|
2021-08-08 01:04:33 -07:00
|
|
|
"no current exe available",
|
2021-06-15 14:27:31 +02:00
|
|
|
));
|
2015-12-02 10:31:29 -08:00
|
|
|
}
|
|
|
|
|
let argv0 = CStr::from_ptr(argv[0]).to_bytes();
|
|
|
|
|
if argv0[0] == b'.' || argv0.iter().any(|b| *b == b'/') {
|
2019-02-11 04:23:21 +09:00
|
|
|
crate::fs::canonicalize(OsStr::from_bytes(argv0))
|
2015-01-29 08:19:28 +01:00
|
|
|
} else {
|
2015-12-02 10:31:29 -08:00
|
|
|
Ok(PathBuf::from(OsStr::from_bytes(argv0)))
|
2015-01-29 08:19:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-26 19:05:10 +00:00
|
|
|
#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
|
2015-02-23 10:59:17 -08:00
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
2019-02-11 04:23:21 +09:00
|
|
|
match crate::fs::read_link("/proc/self/exe") {
|
2021-08-08 01:04:33 -07:00
|
|
|
Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::const_io_error!(
|
2021-06-15 14:27:31 +02:00
|
|
|
io::ErrorKind::Uncategorized,
|
2021-08-08 01:04:33 -07:00
|
|
|
"no /proc/self/exe available. Is /proc mounted?",
|
2019-12-24 17:38:22 -05:00
|
|
|
)),
|
2018-12-05 02:48:18 +01:00
|
|
|
other => other,
|
2017-05-17 15:14:30 +02:00
|
|
|
}
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
|
2023-01-10 10:44:05 +01:00
|
|
|
#[cfg(target_os = "nto")]
|
|
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
|
|
|
|
let mut e = crate::fs::read("/proc/self/exefile")?;
|
|
|
|
|
// Current versions of QNX Neutrino provide a null-terminated path.
|
|
|
|
|
// Ensure the trailing null byte is not returned here.
|
|
|
|
|
if let Some(0) = e.last() {
|
|
|
|
|
e.pop();
|
|
|
|
|
}
|
|
|
|
|
Ok(PathBuf::from(OsString::from_vec(e)))
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-23 16:05:01 +00:00
|
|
|
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
|
2015-02-25 14:15:24 +05:30
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
2014-11-24 16:21:39 -08:00
|
|
|
unsafe {
|
|
|
|
|
let mut sz: u32 = 0;
|
2021-07-25 06:02:07 +01:00
|
|
|
libc::_NSGetExecutablePath(ptr::null_mut(), &mut sz);
|
2019-12-24 17:38:22 -05:00
|
|
|
if sz == 0 {
|
|
|
|
|
return Err(io::Error::last_os_error());
|
|
|
|
|
}
|
2015-03-25 17:06:52 -07:00
|
|
|
let mut v: Vec<u8> = Vec::with_capacity(sz as usize);
|
2021-07-25 06:02:07 +01:00
|
|
|
let err = libc::_NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
|
2019-12-24 17:38:22 -05:00
|
|
|
if err != 0 {
|
|
|
|
|
return Err(io::Error::last_os_error());
|
|
|
|
|
}
|
2015-03-25 17:06:52 -07:00
|
|
|
v.set_len(sz as usize - 1); // chop off trailing NUL
|
2015-03-18 09:14:54 -07:00
|
|
|
Ok(PathBuf::from(OsString::from_vec(v)))
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-13 23:37:22 +00:00
|
|
|
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
|
2016-01-21 19:30:22 +03:00
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
2021-07-30 17:28:44 +01:00
|
|
|
if let Ok(path) = crate::fs::read_link("/proc/self/path/a.out") {
|
|
|
|
|
Ok(path)
|
|
|
|
|
} else {
|
|
|
|
|
unsafe {
|
2022-02-20 08:53:18 +00:00
|
|
|
let path = libc::getexecname();
|
2021-07-30 17:28:44 +01:00
|
|
|
if path.is_null() {
|
|
|
|
|
Err(io::Error::last_os_error())
|
|
|
|
|
} else {
|
|
|
|
|
let filename = CStr::from_ptr(path).to_bytes();
|
|
|
|
|
let path = PathBuf::from(<OsStr as OsStrExt>::from_bytes(filename));
|
2016-01-26 17:15:10 +03:00
|
|
|
|
2021-07-30 17:28:44 +01:00
|
|
|
// Prepend a current working directory to the path if
|
|
|
|
|
// it doesn't contain an absolute pathname.
|
|
|
|
|
if filename[0] == b'/' { Ok(path) } else { getcwd().map(|cwd| cwd.join(path)) }
|
|
|
|
|
}
|
2016-01-21 19:30:22 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-24 23:38:56 -05:00
|
|
|
#[cfg(target_os = "haiku")]
|
|
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
|
|
|
|
unsafe {
|
2021-08-06 07:32:36 +01:00
|
|
|
let mut info: mem::MaybeUninit<libc::image_info> = mem::MaybeUninit::uninit();
|
2016-09-24 23:38:56 -05:00
|
|
|
let mut cookie: i32 = 0;
|
|
|
|
|
// the executable can be found at team id 0
|
2021-08-06 07:32:36 +01:00
|
|
|
let result = libc::_get_next_image_info(
|
|
|
|
|
0,
|
|
|
|
|
&mut cookie,
|
|
|
|
|
info.as_mut_ptr(),
|
|
|
|
|
mem::size_of::<libc::image_info>(),
|
|
|
|
|
);
|
2016-09-24 23:38:56 -05:00
|
|
|
if result != 0 {
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::io::ErrorKind;
|
2021-08-08 01:04:33 -07:00
|
|
|
Err(io::const_io_error!(ErrorKind::Uncategorized, "Error getting executable path"))
|
2016-09-24 23:38:56 -05:00
|
|
|
} else {
|
2021-08-06 07:32:36 +01:00
|
|
|
let name = CStr::from_ptr((*info.as_ptr()).name.as_ptr()).to_bytes();
|
2016-09-24 23:38:56 -05:00
|
|
|
Ok(PathBuf::from(OsStr::from_bytes(name)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-07 08:39:54 -06:00
|
|
|
#[cfg(target_os = "redox")]
|
|
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
|
|
|
|
crate::fs::read_to_string("sys:exe").map(PathBuf::from)
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-18 18:22:32 -04:00
|
|
|
#[cfg(target_os = "l4re")]
|
2016-10-18 13:43:18 -07:00
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::io::ErrorKind;
|
2021-08-08 01:04:33 -07:00
|
|
|
Err(io::const_io_error!(ErrorKind::Unsupported, "Not yet implemented!"))
|
2016-10-18 13:43:18 -07:00
|
|
|
}
|
|
|
|
|
|
2020-10-07 20:38:25 +02:00
|
|
|
#[cfg(target_os = "vxworks")]
|
|
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
use realstd::env;
|
|
|
|
|
|
|
|
|
|
#[cfg(not(test))]
|
|
|
|
|
use crate::env;
|
|
|
|
|
|
|
|
|
|
let exe_path = env::args().next().unwrap();
|
|
|
|
|
let path = path::Path::new(&exe_path);
|
|
|
|
|
path.canonicalize()
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-19 17:59:59 +02:00
|
|
|
#[cfg(any(target_os = "espidf", target_os = "horizon"))]
|
2021-07-29 20:18:22 +03:00
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
|
|
|
|
super::unsupported::unsupported()
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-18 18:22:32 -04:00
|
|
|
#[cfg(target_os = "fuchsia")]
|
|
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
|
|
|
|
use crate::io::ErrorKind;
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
use realstd::env;
|
|
|
|
|
|
|
|
|
|
#[cfg(not(test))]
|
|
|
|
|
use crate::env;
|
|
|
|
|
|
|
|
|
|
let exe_path = env::args().next().ok_or(io::const_io_error!(
|
|
|
|
|
ErrorKind::Uncategorized,
|
|
|
|
|
"an executable path was not found because no arguments were provided through argv"
|
|
|
|
|
))?;
|
|
|
|
|
let path = PathBuf::from(exe_path);
|
|
|
|
|
|
|
|
|
|
// Prepend the current working directory to the path if it's not absolute.
|
|
|
|
|
if !path.is_absolute() { getcwd().map(|cwd| cwd.join(path)) } else { Ok(path) }
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
pub struct Env {
|
|
|
|
|
iter: vec::IntoIter<(OsString, OsString)>,
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-14 04:04:27 +02:00
|
|
|
impl !Send for Env {}
|
|
|
|
|
impl !Sync for Env {}
|
|
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
impl Iterator for Env {
|
|
|
|
|
type Item = (OsString, OsString);
|
2019-12-24 17:38:22 -05:00
|
|
|
fn next(&mut self) -> Option<(OsString, OsString)> {
|
|
|
|
|
self.iter.next()
|
|
|
|
|
}
|
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
|
|
|
self.iter.size_hint()
|
|
|
|
|
}
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
pub unsafe fn environ() -> *mut *const *const c_char {
|
2021-10-07 20:47:17 +01:00
|
|
|
libc::_NSGetEnviron() as *mut *const *const c_char
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(not(target_os = "macos"))]
|
|
|
|
|
pub unsafe fn environ() -> *mut *const *const c_char {
|
2019-12-24 17:38:22 -05:00
|
|
|
extern "C" {
|
|
|
|
|
static mut environ: *const *const c_char;
|
|
|
|
|
}
|
2021-03-14 19:10:34 +01:00
|
|
|
ptr::addr_of_mut!(environ)
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
|
|
|
|
|
2022-08-15 14:33:12 +02:00
|
|
|
static ENV_LOCK: RwLock<()> = RwLock::new(());
|
2021-03-14 19:10:34 +01:00
|
|
|
|
2022-08-15 14:33:12 +02:00
|
|
|
pub fn env_read_lock() -> impl Drop {
|
|
|
|
|
ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner)
|
2018-11-13 14:57:10 -08:00
|
|
|
}
|
|
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
/// Returns a vector of (variable, value) byte-vector pairs for all the
|
|
|
|
|
/// environment variables of the current process.
|
|
|
|
|
pub fn env() -> Env {
|
std: Stabilize APIs for the 1.10 release
This commit applies the FCP decisions made by the libs team for the 1.10 cycle,
including both new stabilizations and deprecations. Specifically, the list of
APIs is:
Stabilized:
* `os::windows::fs::OpenOptionsExt::access_mode`
* `os::windows::fs::OpenOptionsExt::share_mode`
* `os::windows::fs::OpenOptionsExt::custom_flags`
* `os::windows::fs::OpenOptionsExt::attributes`
* `os::windows::fs::OpenOptionsExt::security_qos_flags`
* `os::unix::fs::OpenOptionsExt::custom_flags`
* `sync::Weak::new`
* `Default for sync::Weak`
* `panic::set_hook`
* `panic::take_hook`
* `panic::PanicInfo`
* `panic::PanicInfo::payload`
* `panic::PanicInfo::location`
* `panic::Location`
* `panic::Location::file`
* `panic::Location::line`
* `ffi::CStr::from_bytes_with_nul`
* `ffi::CStr::from_bytes_with_nul_unchecked`
* `ffi::FromBytesWithNulError`
* `fs::Metadata::modified`
* `fs::Metadata::accessed`
* `fs::Metadata::created`
* `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange`
* `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange_weak`
* `collections::{btree,hash}_map::{Occupied,Vacant,}Entry::key`
* `os::unix::net::{UnixStream, UnixListener, UnixDatagram, SocketAddr}`
* `SocketAddr::is_unnamed`
* `SocketAddr::as_pathname`
* `UnixStream::connect`
* `UnixStream::pair`
* `UnixStream::try_clone`
* `UnixStream::local_addr`
* `UnixStream::peer_addr`
* `UnixStream::set_read_timeout`
* `UnixStream::set_write_timeout`
* `UnixStream::read_timeout`
* `UnixStream::write_Timeout`
* `UnixStream::set_nonblocking`
* `UnixStream::take_error`
* `UnixStream::shutdown`
* Read/Write/RawFd impls for `UnixStream`
* `UnixListener::bind`
* `UnixListener::accept`
* `UnixListener::try_clone`
* `UnixListener::local_addr`
* `UnixListener::set_nonblocking`
* `UnixListener::take_error`
* `UnixListener::incoming`
* RawFd impls for `UnixListener`
* `UnixDatagram::bind`
* `UnixDatagram::unbound`
* `UnixDatagram::pair`
* `UnixDatagram::connect`
* `UnixDatagram::try_clone`
* `UnixDatagram::local_addr`
* `UnixDatagram::peer_addr`
* `UnixDatagram::recv_from`
* `UnixDatagram::recv`
* `UnixDatagram::send_to`
* `UnixDatagram::send`
* `UnixDatagram::set_read_timeout`
* `UnixDatagram::set_write_timeout`
* `UnixDatagram::read_timeout`
* `UnixDatagram::write_timeout`
* `UnixDatagram::set_nonblocking`
* `UnixDatagram::take_error`
* `UnixDatagram::shutdown`
* RawFd impls for `UnixDatagram`
* `{BTree,Hash}Map::values_mut`
* `<[_]>::binary_search_by_key`
Deprecated:
* `StaticCondvar` - this, and all other static synchronization primitives
below, are usable today through the lazy-static crate on
stable Rust today. Additionally, we'd like the non-static
versions to be directly usable in a static context one day,
so they're unlikely to be the final forms of the APIs in any
case.
* `CONDVAR_INIT`
* `StaticMutex`
* `MUTEX_INIT`
* `StaticRwLock`
* `RWLOCK_INIT`
* `iter::Peekable::is_empty`
Closes #27717
Closes #27720
cc #27784 (but encode methods still exist)
Closes #30014
Closes #30425
Closes #30449
Closes #31190
Closes #31399
Closes #31767
Closes #32111
Closes #32281
Closes #32312
Closes #32551
Closes #33018
2016-05-17 11:57:07 -07:00
|
|
|
unsafe {
|
2021-03-14 19:10:34 +01:00
|
|
|
let _guard = env_read_lock();
|
2015-01-27 12:20:58 -08:00
|
|
|
let mut environ = *environ();
|
|
|
|
|
let mut result = Vec::new();
|
2020-01-10 12:52:00 +00:00
|
|
|
if !environ.is_null() {
|
|
|
|
|
while !(*environ).is_null() {
|
|
|
|
|
if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
|
|
|
|
|
result.push(key_value);
|
|
|
|
|
}
|
|
|
|
|
environ = environ.add(1);
|
2015-10-25 12:05:34 +00:00
|
|
|
}
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
2021-04-14 04:04:27 +02:00
|
|
|
return Env { iter: result.into_iter() };
|
std: Stabilize APIs for the 1.10 release
This commit applies the FCP decisions made by the libs team for the 1.10 cycle,
including both new stabilizations and deprecations. Specifically, the list of
APIs is:
Stabilized:
* `os::windows::fs::OpenOptionsExt::access_mode`
* `os::windows::fs::OpenOptionsExt::share_mode`
* `os::windows::fs::OpenOptionsExt::custom_flags`
* `os::windows::fs::OpenOptionsExt::attributes`
* `os::windows::fs::OpenOptionsExt::security_qos_flags`
* `os::unix::fs::OpenOptionsExt::custom_flags`
* `sync::Weak::new`
* `Default for sync::Weak`
* `panic::set_hook`
* `panic::take_hook`
* `panic::PanicInfo`
* `panic::PanicInfo::payload`
* `panic::PanicInfo::location`
* `panic::Location`
* `panic::Location::file`
* `panic::Location::line`
* `ffi::CStr::from_bytes_with_nul`
* `ffi::CStr::from_bytes_with_nul_unchecked`
* `ffi::FromBytesWithNulError`
* `fs::Metadata::modified`
* `fs::Metadata::accessed`
* `fs::Metadata::created`
* `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange`
* `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange_weak`
* `collections::{btree,hash}_map::{Occupied,Vacant,}Entry::key`
* `os::unix::net::{UnixStream, UnixListener, UnixDatagram, SocketAddr}`
* `SocketAddr::is_unnamed`
* `SocketAddr::as_pathname`
* `UnixStream::connect`
* `UnixStream::pair`
* `UnixStream::try_clone`
* `UnixStream::local_addr`
* `UnixStream::peer_addr`
* `UnixStream::set_read_timeout`
* `UnixStream::set_write_timeout`
* `UnixStream::read_timeout`
* `UnixStream::write_Timeout`
* `UnixStream::set_nonblocking`
* `UnixStream::take_error`
* `UnixStream::shutdown`
* Read/Write/RawFd impls for `UnixStream`
* `UnixListener::bind`
* `UnixListener::accept`
* `UnixListener::try_clone`
* `UnixListener::local_addr`
* `UnixListener::set_nonblocking`
* `UnixListener::take_error`
* `UnixListener::incoming`
* RawFd impls for `UnixListener`
* `UnixDatagram::bind`
* `UnixDatagram::unbound`
* `UnixDatagram::pair`
* `UnixDatagram::connect`
* `UnixDatagram::try_clone`
* `UnixDatagram::local_addr`
* `UnixDatagram::peer_addr`
* `UnixDatagram::recv_from`
* `UnixDatagram::recv`
* `UnixDatagram::send_to`
* `UnixDatagram::send`
* `UnixDatagram::set_read_timeout`
* `UnixDatagram::set_write_timeout`
* `UnixDatagram::read_timeout`
* `UnixDatagram::write_timeout`
* `UnixDatagram::set_nonblocking`
* `UnixDatagram::take_error`
* `UnixDatagram::shutdown`
* RawFd impls for `UnixDatagram`
* `{BTree,Hash}Map::values_mut`
* `<[_]>::binary_search_by_key`
Deprecated:
* `StaticCondvar` - this, and all other static synchronization primitives
below, are usable today through the lazy-static crate on
stable Rust today. Additionally, we'd like the non-static
versions to be directly usable in a static context one day,
so they're unlikely to be the final forms of the APIs in any
case.
* `CONDVAR_INIT`
* `StaticMutex`
* `MUTEX_INIT`
* `StaticRwLock`
* `RWLOCK_INIT`
* `iter::Peekable::is_empty`
Closes #27717
Closes #27720
cc #27784 (but encode methods still exist)
Closes #30014
Closes #30425
Closes #30449
Closes #31190
Closes #31399
Closes #31767
Closes #32111
Closes #32281
Closes #32312
Closes #32551
Closes #33018
2016-05-17 11:57:07 -07:00
|
|
|
}
|
2015-01-27 12:20:58 -08:00
|
|
|
|
2015-10-25 12:05:34 +00:00
|
|
|
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;
|
|
|
|
|
}
|
2015-12-15 00:03:42 +01:00
|
|
|
let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
|
2019-12-24 17:38:22 -05:00
|
|
|
pos.map(|p| {
|
|
|
|
|
(
|
|
|
|
|
OsStringExt::from_vec(input[..p].to_vec()),
|
|
|
|
|
OsStringExt::from_vec(input[p + 1..].to_vec()),
|
|
|
|
|
)
|
|
|
|
|
})
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 16:04:24 -07:00
|
|
|
pub fn getenv(k: &OsStr) -> Option<OsString> {
|
2015-10-25 10:19:35 -07:00
|
|
|
// environment variables with a nul byte can't be set, so their value is
|
|
|
|
|
// always None as well
|
2022-09-22 04:40:43 -04:00
|
|
|
let s = run_with_cstr(k.as_bytes(), |k| {
|
2021-03-14 19:10:34 +01:00
|
|
|
let _guard = env_read_lock();
|
2022-09-22 04:40:43 -04:00
|
|
|
Ok(unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char)
|
|
|
|
|
})
|
|
|
|
|
.ok()?;
|
|
|
|
|
if s.is_null() {
|
|
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
Some(OsStringExt::from_vec(unsafe { CStr::from_ptr(s) }.to_bytes().to_vec()))
|
std: Stabilize APIs for the 1.10 release
This commit applies the FCP decisions made by the libs team for the 1.10 cycle,
including both new stabilizations and deprecations. Specifically, the list of
APIs is:
Stabilized:
* `os::windows::fs::OpenOptionsExt::access_mode`
* `os::windows::fs::OpenOptionsExt::share_mode`
* `os::windows::fs::OpenOptionsExt::custom_flags`
* `os::windows::fs::OpenOptionsExt::attributes`
* `os::windows::fs::OpenOptionsExt::security_qos_flags`
* `os::unix::fs::OpenOptionsExt::custom_flags`
* `sync::Weak::new`
* `Default for sync::Weak`
* `panic::set_hook`
* `panic::take_hook`
* `panic::PanicInfo`
* `panic::PanicInfo::payload`
* `panic::PanicInfo::location`
* `panic::Location`
* `panic::Location::file`
* `panic::Location::line`
* `ffi::CStr::from_bytes_with_nul`
* `ffi::CStr::from_bytes_with_nul_unchecked`
* `ffi::FromBytesWithNulError`
* `fs::Metadata::modified`
* `fs::Metadata::accessed`
* `fs::Metadata::created`
* `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange`
* `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange_weak`
* `collections::{btree,hash}_map::{Occupied,Vacant,}Entry::key`
* `os::unix::net::{UnixStream, UnixListener, UnixDatagram, SocketAddr}`
* `SocketAddr::is_unnamed`
* `SocketAddr::as_pathname`
* `UnixStream::connect`
* `UnixStream::pair`
* `UnixStream::try_clone`
* `UnixStream::local_addr`
* `UnixStream::peer_addr`
* `UnixStream::set_read_timeout`
* `UnixStream::set_write_timeout`
* `UnixStream::read_timeout`
* `UnixStream::write_Timeout`
* `UnixStream::set_nonblocking`
* `UnixStream::take_error`
* `UnixStream::shutdown`
* Read/Write/RawFd impls for `UnixStream`
* `UnixListener::bind`
* `UnixListener::accept`
* `UnixListener::try_clone`
* `UnixListener::local_addr`
* `UnixListener::set_nonblocking`
* `UnixListener::take_error`
* `UnixListener::incoming`
* RawFd impls for `UnixListener`
* `UnixDatagram::bind`
* `UnixDatagram::unbound`
* `UnixDatagram::pair`
* `UnixDatagram::connect`
* `UnixDatagram::try_clone`
* `UnixDatagram::local_addr`
* `UnixDatagram::peer_addr`
* `UnixDatagram::recv_from`
* `UnixDatagram::recv`
* `UnixDatagram::send_to`
* `UnixDatagram::send`
* `UnixDatagram::set_read_timeout`
* `UnixDatagram::set_write_timeout`
* `UnixDatagram::read_timeout`
* `UnixDatagram::write_timeout`
* `UnixDatagram::set_nonblocking`
* `UnixDatagram::take_error`
* `UnixDatagram::shutdown`
* RawFd impls for `UnixDatagram`
* `{BTree,Hash}Map::values_mut`
* `<[_]>::binary_search_by_key`
Deprecated:
* `StaticCondvar` - this, and all other static synchronization primitives
below, are usable today through the lazy-static crate on
stable Rust today. Additionally, we'd like the non-static
versions to be directly usable in a static context one day,
so they're unlikely to be the final forms of the APIs in any
case.
* `CONDVAR_INIT`
* `StaticMutex`
* `MUTEX_INIT`
* `StaticRwLock`
* `RWLOCK_INIT`
* `iter::Peekable::is_empty`
Closes #27717
Closes #27720
cc #27784 (but encode methods still exist)
Closes #30014
Closes #30425
Closes #30449
Closes #31190
Closes #31399
Closes #31767
Closes #32111
Closes #32281
Closes #32312
Closes #32551
Closes #33018
2016-05-17 11:57:07 -07:00
|
|
|
}
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
|
|
|
|
|
2015-10-25 10:19:35 -07:00
|
|
|
pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
|
2022-09-22 04:40:43 -04:00
|
|
|
run_with_cstr(k.as_bytes(), |k| {
|
|
|
|
|
run_with_cstr(v.as_bytes(), |v| {
|
|
|
|
|
let _guard = ENV_LOCK.write();
|
|
|
|
|
cvt(unsafe { libc::setenv(k.as_ptr(), v.as_ptr(), 1) }).map(drop)
|
|
|
|
|
})
|
|
|
|
|
})
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
2015-01-27 12:20:58 -08:00
|
|
|
|
2015-10-25 10:19:35 -07:00
|
|
|
pub fn unsetenv(n: &OsStr) -> io::Result<()> {
|
2022-09-22 04:40:43 -04:00
|
|
|
run_with_cstr(n.as_bytes(), |nbuf| {
|
2021-04-29 09:53:19 +02:00
|
|
|
let _guard = ENV_LOCK.write();
|
2022-09-22 04:40:43 -04:00
|
|
|
cvt(unsafe { libc::unsetenv(nbuf.as_ptr()) }).map(drop)
|
|
|
|
|
})
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
|
2021-07-29 20:18:22 +03:00
|
|
|
#[cfg(not(target_os = "espidf"))]
|
2015-01-27 12:20:58 -08:00
|
|
|
pub fn page_size() -> usize {
|
2019-12-24 17:38:22 -05:00
|
|
|
unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
2015-01-27 12:20:58 -08:00
|
|
|
|
2015-02-23 10:59:17 -08:00
|
|
|
pub fn temp_dir() -> PathBuf {
|
2019-02-11 04:23:21 +09:00
|
|
|
crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
|
2015-01-27 12:20:58 -08:00
|
|
|
if cfg!(target_os = "android") {
|
2015-03-18 09:14:54 -07:00
|
|
|
PathBuf::from("/data/local/tmp")
|
2015-01-27 12:20:58 -08:00
|
|
|
} else {
|
2015-03-18 09:14:54 -07:00
|
|
|
PathBuf::from("/tmp")
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 10:59:17 -08:00
|
|
|
pub fn home_dir() -> Option<PathBuf> {
|
2019-12-24 17:38:22 -05:00
|
|
|
return crate::env::var_os("HOME").or_else(|| unsafe { fallback() }).map(PathBuf::from);
|
|
|
|
|
|
|
|
|
|
#[cfg(any(
|
|
|
|
|
target_os = "android",
|
|
|
|
|
target_os = "ios",
|
2022-03-23 16:05:01 +00:00
|
|
|
target_os = "watchos",
|
2019-12-24 17:38:22 -05:00
|
|
|
target_os = "emscripten",
|
2020-10-07 20:38:25 +02:00
|
|
|
target_os = "redox",
|
2021-07-29 20:18:22 +03:00
|
|
|
target_os = "vxworks",
|
2021-10-19 17:59:59 +02:00
|
|
|
target_os = "espidf",
|
|
|
|
|
target_os = "horizon"
|
2019-12-24 17:38:22 -05:00
|
|
|
))]
|
|
|
|
|
unsafe fn fallback() -> Option<OsString> {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
#[cfg(not(any(
|
|
|
|
|
target_os = "android",
|
|
|
|
|
target_os = "ios",
|
2022-03-23 16:05:01 +00:00
|
|
|
target_os = "watchos",
|
2019-12-24 17:38:22 -05:00
|
|
|
target_os = "emscripten",
|
2020-10-07 20:38:25 +02:00
|
|
|
target_os = "redox",
|
2021-07-29 20:18:22 +03:00
|
|
|
target_os = "vxworks",
|
2021-10-19 17:59:59 +02:00
|
|
|
target_os = "espidf",
|
|
|
|
|
target_os = "horizon"
|
2019-12-24 17:38:22 -05:00
|
|
|
)))]
|
2015-02-02 11:04:58 -08:00
|
|
|
unsafe fn fallback() -> Option<OsString> {
|
2015-11-02 16:23:22 -08:00
|
|
|
let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
|
2015-01-27 12:20:58 -08:00
|
|
|
n if n < 0 => 512 as usize,
|
|
|
|
|
n => n as usize,
|
|
|
|
|
};
|
2016-08-27 21:01:27 +02:00
|
|
|
let mut buf = Vec::with_capacity(amt);
|
|
|
|
|
let mut passwd: libc::passwd = mem::zeroed();
|
2017-02-15 22:52:47 -08:00
|
|
|
let mut result = ptr::null_mut();
|
2019-12-24 17:38:22 -05:00
|
|
|
match libc::getpwuid_r(
|
|
|
|
|
libc::getuid(),
|
|
|
|
|
&mut passwd,
|
|
|
|
|
buf.as_mut_ptr(),
|
|
|
|
|
buf.capacity(),
|
|
|
|
|
&mut result,
|
|
|
|
|
) {
|
2017-02-15 22:52:47 -08:00
|
|
|
0 if !result.is_null() => {
|
|
|
|
|
let ptr = passwd.pw_dir as *const _;
|
|
|
|
|
let bytes = CStr::from_ptr(ptr).to_bytes().to_vec();
|
|
|
|
|
Some(OsStringExt::from_vec(bytes))
|
2019-12-24 17:38:22 -05:00
|
|
|
}
|
2017-02-15 22:52:47 -08:00
|
|
|
_ => None,
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
2015-02-02 11:04:58 -08:00
|
|
|
}
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
2015-03-31 14:41:59 -07:00
|
|
|
|
|
|
|
|
pub fn exit(code: i32) -> ! {
|
|
|
|
|
unsafe { libc::exit(code as c_int) }
|
|
|
|
|
}
|
2017-10-05 23:49:36 -06:00
|
|
|
|
|
|
|
|
pub fn getpid() -> u32 {
|
|
|
|
|
unsafe { libc::getpid() as u32 }
|
|
|
|
|
}
|
2017-11-18 21:09:18 -08:00
|
|
|
|
|
|
|
|
pub fn getppid() -> u32 {
|
|
|
|
|
unsafe { libc::getppid() as u32 }
|
|
|
|
|
}
|
2018-03-02 12:50:07 -08:00
|
|
|
|
Refactor weak symbols in std::sys::unix
This makes a few changes to the weak symbol macros in `sys::unix`:
- `dlsym!` is added to keep the functionality for runtime `dlsym`
lookups, like for `__pthread_get_minstack@GLIBC_PRIVATE` that we don't
want to show up in ELF symbol tables.
- `weak!` now uses `#[linkage = "extern_weak"]` symbols, so its runtime
behavior is just a simple null check. This is also used by `syscall!`.
- On non-ELF targets (macos/ios) where that linkage is not known to
behave, `weak!` is just an alias to `dlsym!` for the old behavior.
- `raw_syscall!` is added to always call `libc::syscall` on linux and
android, for cases like `clone3` that have no known libc wrapper.
The new `weak!` linkage does mean that you'll get versioned symbols if
you build with a newer glibc, like `WEAK DEFAULT UND statx@GLIBC_2.28`.
This might seem problematic, but old non-weak symbols can tie the build
to new versions too, like `dlsym@GLIBC_2.34` from their recent library
unification. If you build with an old glibc like `dist-x86_64-linux`
does, you'll still get unversioned `WEAK DEFAULT UND statx`, which may
be resolved based on the runtime glibc.
I also found a few functions that don't need to be weak anymore:
- Android can directly use `ftruncate64`, `pread64`, and `pwrite64`, as
these were added in API 12, and our baseline is API 14.
- Linux can directly use `splice`, added way back in glibc 2.5 and
similarly old musl. Android only added it in API 21 though.
2021-11-12 12:58:38 -08:00
|
|
|
#[cfg(all(target_os = "linux", target_env = "gnu"))]
|
2018-03-02 12:50:07 -08:00
|
|
|
pub fn glibc_version() -> Option<(usize, usize)> {
|
Refactor weak symbols in std::sys::unix
This makes a few changes to the weak symbol macros in `sys::unix`:
- `dlsym!` is added to keep the functionality for runtime `dlsym`
lookups, like for `__pthread_get_minstack@GLIBC_PRIVATE` that we don't
want to show up in ELF symbol tables.
- `weak!` now uses `#[linkage = "extern_weak"]` symbols, so its runtime
behavior is just a simple null check. This is also used by `syscall!`.
- On non-ELF targets (macos/ios) where that linkage is not known to
behave, `weak!` is just an alias to `dlsym!` for the old behavior.
- `raw_syscall!` is added to always call `libc::syscall` on linux and
android, for cases like `clone3` that have no known libc wrapper.
The new `weak!` linkage does mean that you'll get versioned symbols if
you build with a newer glibc, like `WEAK DEFAULT UND statx@GLIBC_2.28`.
This might seem problematic, but old non-weak symbols can tie the build
to new versions too, like `dlsym@GLIBC_2.34` from their recent library
unification. If you build with an old glibc like `dist-x86_64-linux`
does, you'll still get unversioned `WEAK DEFAULT UND statx`, which may
be resolved based on the runtime glibc.
I also found a few functions that don't need to be weak anymore:
- Android can directly use `ftruncate64`, `pread64`, and `pwrite64`, as
these were added in API 12, and our baseline is API 14.
- Linux can directly use `splice`, added way back in glibc 2.5 and
similarly old musl. Android only added it in API 21 though.
2021-11-12 12:58:38 -08:00
|
|
|
extern "C" {
|
|
|
|
|
fn gnu_get_libc_version() -> *const libc::c_char;
|
2018-03-02 12:50:07 -08:00
|
|
|
}
|
Refactor weak symbols in std::sys::unix
This makes a few changes to the weak symbol macros in `sys::unix`:
- `dlsym!` is added to keep the functionality for runtime `dlsym`
lookups, like for `__pthread_get_minstack@GLIBC_PRIVATE` that we don't
want to show up in ELF symbol tables.
- `weak!` now uses `#[linkage = "extern_weak"]` symbols, so its runtime
behavior is just a simple null check. This is also used by `syscall!`.
- On non-ELF targets (macos/ios) where that linkage is not known to
behave, `weak!` is just an alias to `dlsym!` for the old behavior.
- `raw_syscall!` is added to always call `libc::syscall` on linux and
android, for cases like `clone3` that have no known libc wrapper.
The new `weak!` linkage does mean that you'll get versioned symbols if
you build with a newer glibc, like `WEAK DEFAULT UND statx@GLIBC_2.28`.
This might seem problematic, but old non-weak symbols can tie the build
to new versions too, like `dlsym@GLIBC_2.34` from their recent library
unification. If you build with an old glibc like `dist-x86_64-linux`
does, you'll still get unversioned `WEAK DEFAULT UND statx`, which may
be resolved based on the runtime glibc.
I also found a few functions that don't need to be weak anymore:
- Android can directly use `ftruncate64`, `pread64`, and `pwrite64`, as
these were added in API 12, and our baseline is API 14.
- Linux can directly use `splice`, added way back in glibc 2.5 and
similarly old musl. Android only added it in API 21 though.
2021-11-12 12:58:38 -08:00
|
|
|
let version_cstr = unsafe { CStr::from_ptr(gnu_get_libc_version()) };
|
|
|
|
|
if let Ok(version_str) = version_cstr.to_str() {
|
|
|
|
|
parse_glibc_version(version_str)
|
2018-03-02 12:50:07 -08:00
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Returns Some((major, minor)) if the string is a valid "x.y" version,
|
|
|
|
|
// ignoring any extra dot-separated parts. Otherwise return None.
|
Refactor weak symbols in std::sys::unix
This makes a few changes to the weak symbol macros in `sys::unix`:
- `dlsym!` is added to keep the functionality for runtime `dlsym`
lookups, like for `__pthread_get_minstack@GLIBC_PRIVATE` that we don't
want to show up in ELF symbol tables.
- `weak!` now uses `#[linkage = "extern_weak"]` symbols, so its runtime
behavior is just a simple null check. This is also used by `syscall!`.
- On non-ELF targets (macos/ios) where that linkage is not known to
behave, `weak!` is just an alias to `dlsym!` for the old behavior.
- `raw_syscall!` is added to always call `libc::syscall` on linux and
android, for cases like `clone3` that have no known libc wrapper.
The new `weak!` linkage does mean that you'll get versioned symbols if
you build with a newer glibc, like `WEAK DEFAULT UND statx@GLIBC_2.28`.
This might seem problematic, but old non-weak symbols can tie the build
to new versions too, like `dlsym@GLIBC_2.34` from their recent library
unification. If you build with an old glibc like `dist-x86_64-linux`
does, you'll still get unversioned `WEAK DEFAULT UND statx`, which may
be resolved based on the runtime glibc.
I also found a few functions that don't need to be weak anymore:
- Android can directly use `ftruncate64`, `pread64`, and `pwrite64`, as
these were added in API 12, and our baseline is API 14.
- Linux can directly use `splice`, added way back in glibc 2.5 and
similarly old musl. Android only added it in API 21 though.
2021-11-12 12:58:38 -08:00
|
|
|
#[cfg(all(target_os = "linux", target_env = "gnu"))]
|
2018-03-02 12:50:07 -08:00
|
|
|
fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
|
2018-07-23 15:32:57 +02:00
|
|
|
let mut parsed_ints = version.split('.').map(str::parse::<usize>).fuse();
|
2018-03-02 12:50:07 -08:00
|
|
|
match (parsed_ints.next(), parsed_ints.next()) {
|
|
|
|
|
(Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)),
|
2019-12-24 17:38:22 -05:00
|
|
|
_ => None,
|
2018-03-02 12:50:07 -08:00
|
|
|
}
|
|
|
|
|
}
|