1#![allow(unused_imports)] #[cfg(test)]
6mod tests;
7
8use core::slice::memchr;
9
10use libc::{c_char, c_int, c_void};
11
12use crate::error::Error as StdError;
13use crate::ffi::{CStr, CString, OsStr, OsString};
14use crate::os::unix::prelude::*;
15use crate::path::{self, PathBuf};
16use crate::sync::{PoisonError, RwLock};
17use crate::sys::common::small_c_string::{run_path_with_cstr, run_with_cstr};
18#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
19use crate::sys::weak::weak;
20use crate::sys::{cvt, fd};
21use crate::{fmt, io, iter, mem, ptr, slice, str, vec};
22
23const TMPBUF_SZ: usize = 128;
24
25cfg_if::cfg_if! {
26 if #[cfg(target_os = "redox")] {
27 const PATH_SEPARATOR: u8 = b';';
28 } else {
29 const PATH_SEPARATOR: u8 = b':';
30 }
31}
32
33unsafe extern "C" {
34 #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))]
35 #[cfg_attr(
36 any(
37 target_os = "linux",
38 target_os = "emscripten",
39 target_os = "fuchsia",
40 target_os = "l4re",
41 target_os = "hurd",
42 ),
43 link_name = "__errno_location"
44 )]
45 #[cfg_attr(
46 any(
47 target_os = "netbsd",
48 target_os = "openbsd",
49 target_os = "cygwin",
50 target_os = "android",
51 target_os = "redox",
52 target_os = "nuttx",
53 target_env = "newlib"
54 ),
55 link_name = "__errno"
56 )]
57 #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")]
58 #[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")]
59 #[cfg_attr(any(target_os = "freebsd", target_vendor = "apple"), link_name = "__error")]
60 #[cfg_attr(target_os = "haiku", link_name = "_errnop")]
61 #[cfg_attr(target_os = "aix", link_name = "_Errno")]
62 #[unsafe(ffi_const)]
64 fn errno_location() -> *mut c_int;
65}
66
67#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))]
69#[inline]
70pub fn errno() -> i32 {
71 unsafe { (*errno_location()) as i32 }
72}
73
74#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks"), not(target_os = "rtems")))]
77#[allow(dead_code)] #[inline]
79pub fn set_errno(e: i32) {
80 unsafe { *errno_location() = e as c_int }
81}
82
83#[cfg(target_os = "vxworks")]
84#[inline]
85pub fn errno() -> i32 {
86 unsafe { libc::errnoGet() }
87}
88
89#[cfg(target_os = "rtems")]
90#[inline]
91pub fn errno() -> i32 {
92 unsafe extern "C" {
93 #[thread_local]
94 static _tls_errno: c_int;
95 }
96
97 unsafe { _tls_errno as i32 }
98}
99
100#[cfg(target_os = "dragonfly")]
101#[inline]
102pub fn errno() -> i32 {
103 unsafe extern "C" {
104 #[thread_local]
105 static errno: c_int;
106 }
107
108 unsafe { errno as i32 }
109}
110
111#[cfg(target_os = "dragonfly")]
112#[allow(dead_code)]
113#[inline]
114pub fn set_errno(e: i32) {
115 unsafe extern "C" {
116 #[thread_local]
117 static mut errno: c_int;
118 }
119
120 unsafe {
121 errno = e;
122 }
123}
124
125pub fn error_string(errno: i32) -> String {
127 unsafe extern "C" {
128 #[cfg_attr(
129 all(
130 any(
131 target_os = "linux",
132 target_os = "hurd",
133 target_env = "newlib",
134 target_os = "cygwin"
135 ),
136 not(target_env = "ohos")
137 ),
138 link_name = "__xpg_strerror_r"
139 )]
140 fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) -> c_int;
141 }
142
143 let mut buf = [0 as c_char; TMPBUF_SZ];
144
145 let p = buf.as_mut_ptr();
146 unsafe {
147 if strerror_r(errno as c_int, p, buf.len()) < 0 {
148 panic!("strerror_r failure");
149 }
150
151 let p = p as *const _;
152 String::from_utf8_lossy(CStr::from_ptr(p).to_bytes()).into()
155 }
156}
157
158#[cfg(target_os = "espidf")]
159pub fn getcwd() -> io::Result<PathBuf> {
160 Ok(PathBuf::from("/"))
161}
162
163#[cfg(not(target_os = "espidf"))]
164pub fn getcwd() -> io::Result<PathBuf> {
165 let mut buf = Vec::with_capacity(512);
166 loop {
167 unsafe {
168 let ptr = buf.as_mut_ptr() as *mut libc::c_char;
169 if !libc::getcwd(ptr, buf.capacity()).is_null() {
170 let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len();
171 buf.set_len(len);
172 buf.shrink_to_fit();
173 return Ok(PathBuf::from(OsString::from_vec(buf)));
174 } else {
175 let error = io::Error::last_os_error();
176 if error.raw_os_error() != Some(libc::ERANGE) {
177 return Err(error);
178 }
179 }
180
181 let cap = buf.capacity();
184 buf.set_len(cap);
185 buf.reserve(1);
186 }
187 }
188}
189
190#[cfg(target_os = "espidf")]
191pub fn chdir(_p: &path::Path) -> io::Result<()> {
192 super::unsupported::unsupported()
193}
194
195#[cfg(not(target_os = "espidf"))]
196pub fn chdir(p: &path::Path) -> io::Result<()> {
197 let result = run_path_with_cstr(p, &|p| unsafe { Ok(libc::chdir(p.as_ptr())) })?;
198 if result == 0 { Ok(()) } else { Err(io::Error::last_os_error()) }
199}
200
201pub struct SplitPaths<'a> {
202 iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>, fn(&'a [u8]) -> PathBuf>,
203}
204
205pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
206 fn bytes_to_path(b: &[u8]) -> PathBuf {
207 PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
208 }
209 fn is_separator(b: &u8) -> bool {
210 *b == PATH_SEPARATOR
211 }
212 let unparsed = unparsed.as_bytes();
213 SplitPaths {
214 iter: unparsed
215 .split(is_separator as fn(&u8) -> bool)
216 .map(bytes_to_path as fn(&[u8]) -> PathBuf),
217 }
218}
219
220impl<'a> Iterator for SplitPaths<'a> {
221 type Item = PathBuf;
222 fn next(&mut self) -> Option<PathBuf> {
223 self.iter.next()
224 }
225 fn size_hint(&self) -> (usize, Option<usize>) {
226 self.iter.size_hint()
227 }
228}
229
230#[derive(Debug)]
231pub struct JoinPathsError;
232
233pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
234where
235 I: Iterator<Item = T>,
236 T: AsRef<OsStr>,
237{
238 let mut joined = Vec::new();
239
240 for (i, path) in paths.enumerate() {
241 let path = path.as_ref().as_bytes();
242 if i > 0 {
243 joined.push(PATH_SEPARATOR)
244 }
245 if path.contains(&PATH_SEPARATOR) {
246 return Err(JoinPathsError);
247 }
248 joined.extend_from_slice(path);
249 }
250 Ok(OsStringExt::from_vec(joined))
251}
252
253impl fmt::Display for JoinPathsError {
254 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255 write!(f, "path segment contains separator `{}`", char::from(PATH_SEPARATOR))
256 }
257}
258
259impl StdError for JoinPathsError {
260 #[allow(deprecated)]
261 fn description(&self) -> &str {
262 "failed to join paths"
263 }
264}
265
266#[cfg(target_os = "aix")]
267pub fn current_exe() -> io::Result<PathBuf> {
268 #[cfg(test)]
269 use realstd::env;
270
271 #[cfg(not(test))]
272 use crate::env;
273 use crate::io::ErrorKind;
274
275 let exe_path = env::args().next().ok_or(io::const_error!(
276 ErrorKind::NotFound,
277 "an executable path was not found because no arguments were provided through argv",
278 ))?;
279 let path = PathBuf::from(exe_path);
280 if path.is_absolute() {
281 return path.canonicalize();
282 }
283 if let Some(pstr) = path.to_str()
285 && pstr.contains("/")
286 {
287 return getcwd().map(|cwd| cwd.join(path))?.canonicalize();
288 }
289 if let Some(p) = getenv(OsStr::from_bytes("PATH".as_bytes())) {
291 for search_path in split_paths(&p) {
292 let pb = search_path.join(&path);
293 if pb.is_file()
294 && let Ok(metadata) = crate::fs::metadata(&pb)
295 && metadata.permissions().mode() & 0o111 != 0
296 {
297 return pb.canonicalize();
298 }
299 }
300 }
301 Err(io::const_error!(ErrorKind::NotFound, "an executable path was not found"))
302}
303
304#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
305pub fn current_exe() -> io::Result<PathBuf> {
306 unsafe {
307 let mut mib = [
308 libc::CTL_KERN as c_int,
309 libc::KERN_PROC as c_int,
310 libc::KERN_PROC_PATHNAME as c_int,
311 -1 as c_int,
312 ];
313 let mut sz = 0;
314 cvt(libc::sysctl(
315 mib.as_mut_ptr(),
316 mib.len() as libc::c_uint,
317 ptr::null_mut(),
318 &mut sz,
319 ptr::null_mut(),
320 0,
321 ))?;
322 if sz == 0 {
323 return Err(io::Error::last_os_error());
324 }
325 let mut v: Vec<u8> = Vec::with_capacity(sz);
326 cvt(libc::sysctl(
327 mib.as_mut_ptr(),
328 mib.len() as libc::c_uint,
329 v.as_mut_ptr() as *mut libc::c_void,
330 &mut sz,
331 ptr::null_mut(),
332 0,
333 ))?;
334 if sz == 0 {
335 return Err(io::Error::last_os_error());
336 }
337 v.set_len(sz - 1); Ok(PathBuf::from(OsString::from_vec(v)))
339 }
340}
341
342#[cfg(target_os = "netbsd")]
343pub fn current_exe() -> io::Result<PathBuf> {
344 fn sysctl() -> io::Result<PathBuf> {
345 unsafe {
346 let mib = [libc::CTL_KERN, libc::KERN_PROC_ARGS, -1, libc::KERN_PROC_PATHNAME];
347 let mut path_len: usize = 0;
348 cvt(libc::sysctl(
349 mib.as_ptr(),
350 mib.len() as libc::c_uint,
351 ptr::null_mut(),
352 &mut path_len,
353 ptr::null(),
354 0,
355 ))?;
356 if path_len <= 1 {
357 return Err(io::const_error!(
358 io::ErrorKind::Uncategorized,
359 "KERN_PROC_PATHNAME sysctl returned zero-length string",
360 ));
361 }
362 let mut path: Vec<u8> = Vec::with_capacity(path_len);
363 cvt(libc::sysctl(
364 mib.as_ptr(),
365 mib.len() as libc::c_uint,
366 path.as_ptr() as *mut libc::c_void,
367 &mut path_len,
368 ptr::null(),
369 0,
370 ))?;
371 path.set_len(path_len - 1); Ok(PathBuf::from(OsString::from_vec(path)))
373 }
374 }
375 fn procfs() -> io::Result<PathBuf> {
376 let curproc_exe = path::Path::new("/proc/curproc/exe");
377 if curproc_exe.is_file() {
378 return crate::fs::read_link(curproc_exe);
379 }
380 Err(io::const_error!(
381 io::ErrorKind::Uncategorized,
382 "/proc/curproc/exe doesn't point to regular file.",
383 ))
384 }
385 sysctl().or_else(|_| procfs())
386}
387
388#[cfg(target_os = "openbsd")]
389pub fn current_exe() -> io::Result<PathBuf> {
390 unsafe {
391 let mut mib = [libc::CTL_KERN, libc::KERN_PROC_ARGS, libc::getpid(), libc::KERN_PROC_ARGV];
392 let mib = mib.as_mut_ptr();
393 let mut argv_len = 0;
394 cvt(libc::sysctl(mib, 4, ptr::null_mut(), &mut argv_len, ptr::null_mut(), 0))?;
395 let mut argv = Vec::<*const libc::c_char>::with_capacity(argv_len as usize);
396 cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _, &mut argv_len, ptr::null_mut(), 0))?;
397 argv.set_len(argv_len as usize);
398 if argv[0].is_null() {
399 return Err(io::const_error!(io::ErrorKind::Uncategorized, "no current exe available"));
400 }
401 let argv0 = CStr::from_ptr(argv[0]).to_bytes();
402 if argv0[0] == b'.' || argv0.iter().any(|b| *b == b'/') {
403 crate::fs::canonicalize(OsStr::from_bytes(argv0))
404 } else {
405 Ok(PathBuf::from(OsStr::from_bytes(argv0)))
406 }
407 }
408}
409
410#[cfg(any(
411 target_os = "linux",
412 target_os = "cygwin",
413 target_os = "hurd",
414 target_os = "android",
415 target_os = "nuttx",
416 target_os = "emscripten"
417))]
418pub fn current_exe() -> io::Result<PathBuf> {
419 match crate::fs::read_link("/proc/self/exe") {
420 Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::const_error!(
421 io::ErrorKind::Uncategorized,
422 "no /proc/self/exe available. Is /proc mounted?",
423 )),
424 other => other,
425 }
426}
427
428#[cfg(target_os = "nto")]
429pub fn current_exe() -> io::Result<PathBuf> {
430 let mut e = crate::fs::read("/proc/self/exefile")?;
431 if let Some(0) = e.last() {
434 e.pop();
435 }
436 Ok(PathBuf::from(OsString::from_vec(e)))
437}
438
439#[cfg(target_vendor = "apple")]
440pub fn current_exe() -> io::Result<PathBuf> {
441 unsafe {
442 let mut sz: u32 = 0;
443 #[expect(deprecated)]
444 libc::_NSGetExecutablePath(ptr::null_mut(), &mut sz);
445 if sz == 0 {
446 return Err(io::Error::last_os_error());
447 }
448 let mut v: Vec<u8> = Vec::with_capacity(sz as usize);
449 #[expect(deprecated)]
450 let err = libc::_NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
451 if err != 0 {
452 return Err(io::Error::last_os_error());
453 }
454 v.set_len(sz as usize - 1); Ok(PathBuf::from(OsString::from_vec(v)))
456 }
457}
458
459#[cfg(any(target_os = "solaris", target_os = "illumos"))]
460pub fn current_exe() -> io::Result<PathBuf> {
461 if let Ok(path) = crate::fs::read_link("/proc/self/path/a.out") {
462 Ok(path)
463 } else {
464 unsafe {
465 let path = libc::getexecname();
466 if path.is_null() {
467 Err(io::Error::last_os_error())
468 } else {
469 let filename = CStr::from_ptr(path).to_bytes();
470 let path = PathBuf::from(<OsStr as OsStrExt>::from_bytes(filename));
471
472 if filename[0] == b'/' { Ok(path) } else { getcwd().map(|cwd| cwd.join(path)) }
475 }
476 }
477 }
478}
479
480#[cfg(target_os = "haiku")]
481pub fn current_exe() -> io::Result<PathBuf> {
482 let mut name = vec![0; libc::PATH_MAX as usize];
483 unsafe {
484 let result = libc::find_path(
485 crate::ptr::null_mut(),
486 libc::path_base_directory::B_FIND_PATH_IMAGE_PATH,
487 crate::ptr::null_mut(),
488 name.as_mut_ptr(),
489 name.len(),
490 );
491 if result != libc::B_OK {
492 use crate::io::ErrorKind;
493 Err(io::const_error!(ErrorKind::Uncategorized, "error getting executable path"))
494 } else {
495 let name = CStr::from_ptr(name.as_ptr()).to_bytes();
497 Ok(PathBuf::from(OsStr::from_bytes(name)))
498 }
499 }
500}
501
502#[cfg(target_os = "redox")]
503pub fn current_exe() -> io::Result<PathBuf> {
504 crate::fs::read_to_string("/scheme/sys/exe").map(PathBuf::from)
505}
506
507#[cfg(target_os = "rtems")]
508pub fn current_exe() -> io::Result<PathBuf> {
509 crate::fs::read_to_string("sys:exe").map(PathBuf::from)
510}
511
512#[cfg(target_os = "l4re")]
513pub fn current_exe() -> io::Result<PathBuf> {
514 use crate::io::ErrorKind;
515 Err(io::const_error!(ErrorKind::Unsupported, "not yet implemented!"))
516}
517
518#[cfg(target_os = "vxworks")]
519pub fn current_exe() -> io::Result<PathBuf> {
520 #[cfg(test)]
521 use realstd::env;
522
523 #[cfg(not(test))]
524 use crate::env;
525
526 let exe_path = env::args().next().unwrap();
527 let path = path::Path::new(&exe_path);
528 path.canonicalize()
529}
530
531#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))]
532pub fn current_exe() -> io::Result<PathBuf> {
533 super::unsupported::unsupported()
534}
535
536#[cfg(target_os = "fuchsia")]
537pub fn current_exe() -> io::Result<PathBuf> {
538 #[cfg(test)]
539 use realstd::env;
540
541 #[cfg(not(test))]
542 use crate::env;
543 use crate::io::ErrorKind;
544
545 let exe_path = env::args().next().ok_or(io::const_error!(
546 ErrorKind::Uncategorized,
547 "an executable path was not found because no arguments were provided through argv",
548 ))?;
549 let path = PathBuf::from(exe_path);
550
551 if !path.is_absolute() { getcwd().map(|cwd| cwd.join(path)) } else { Ok(path) }
553}
554
555pub struct Env {
556 iter: vec::IntoIter<(OsString, OsString)>,
557}
558
559pub struct EnvStrDebug<'a> {
561 slice: &'a [(OsString, OsString)],
562}
563
564impl fmt::Debug for EnvStrDebug<'_> {
565 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
566 let Self { slice } = self;
567 f.debug_list()
568 .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap())))
569 .finish()
570 }
571}
572
573impl Env {
574 pub fn str_debug(&self) -> impl fmt::Debug + '_ {
575 let Self { iter } = self;
576 EnvStrDebug { slice: iter.as_slice() }
577 }
578}
579
580impl fmt::Debug for Env {
581 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
582 let Self { iter } = self;
583 f.debug_list().entries(iter.as_slice()).finish()
584 }
585}
586
587impl !Send for Env {}
588impl !Sync for Env {}
589
590impl Iterator for Env {
591 type Item = (OsString, OsString);
592 fn next(&mut self) -> Option<(OsString, OsString)> {
593 self.iter.next()
594 }
595 fn size_hint(&self) -> (usize, Option<usize>) {
596 self.iter.size_hint()
597 }
598}
599
600#[cfg(target_vendor = "apple")]
624pub unsafe fn environ() -> *mut *const *const c_char {
625 libc::_NSGetEnviron() as *mut *const *const c_char
626}
627
628#[cfg(not(target_vendor = "apple"))]
630pub unsafe fn environ() -> *mut *const *const c_char {
631 unsafe extern "C" {
632 static mut environ: *const *const c_char;
633 }
634 &raw mut environ
635}
636
637static ENV_LOCK: RwLock<()> = RwLock::new(());
638
639pub fn env_read_lock() -> impl Drop {
640 ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner)
641}
642
643pub fn env() -> Env {
646 unsafe {
647 let _guard = env_read_lock();
648 let mut environ = *environ();
649 let mut result = Vec::new();
650 if !environ.is_null() {
651 while !(*environ).is_null() {
652 if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
653 result.push(key_value);
654 }
655 environ = environ.add(1);
656 }
657 }
658 return Env { iter: result.into_iter() };
659 }
660
661 fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
662 if input.is_empty() {
667 return None;
668 }
669 let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
670 pos.map(|p| {
671 (
672 OsStringExt::from_vec(input[..p].to_vec()),
673 OsStringExt::from_vec(input[p + 1..].to_vec()),
674 )
675 })
676 }
677}
678
679pub fn getenv(k: &OsStr) -> Option<OsString> {
680 run_with_cstr(k.as_bytes(), &|k| {
683 let _guard = env_read_lock();
684 let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char;
685
686 if v.is_null() {
687 Ok(None)
688 } else {
689 let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec();
691
692 Ok(Some(OsStringExt::from_vec(bytes)))
693 }
694 })
695 .ok()
696 .flatten()
697}
698
699pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
700 run_with_cstr(k.as_bytes(), &|k| {
701 run_with_cstr(v.as_bytes(), &|v| {
702 let _guard = ENV_LOCK.write();
703 cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop)
704 })
705 })
706}
707
708pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> {
709 run_with_cstr(n.as_bytes(), &|nbuf| {
710 let _guard = ENV_LOCK.write();
711 cvt(libc::unsetenv(nbuf.as_ptr())).map(drop)
712 })
713}
714
715#[cfg(not(target_os = "espidf"))]
716pub fn page_size() -> usize {
717 unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
718}
719
720#[cfg(all(target_vendor = "apple", not(miri)))]
729fn confstr(key: c_int, size_hint: Option<usize>) -> io::Result<OsString> {
730 let mut buf: Vec<u8> = Vec::with_capacity(0);
731 let mut bytes_needed_including_nul = size_hint
732 .unwrap_or_else(|| {
733 unsafe { libc::confstr(key, core::ptr::null_mut(), 0) }
738 })
739 .max(1);
740 while bytes_needed_including_nul > buf.capacity() {
745 buf.reserve(bytes_needed_including_nul);
751 bytes_needed_including_nul =
758 unsafe { libc::confstr(key, buf.as_mut_ptr().cast::<c_char>(), buf.capacity()) };
759 }
760 if bytes_needed_including_nul == 0 {
762 return Err(io::Error::last_os_error());
763 }
764 unsafe {
768 buf.set_len(bytes_needed_including_nul);
769 let last_byte = buf.pop();
771 assert_eq!(last_byte, Some(0), "`confstr` provided a string which wasn't nul-terminated");
773 };
774 Ok(OsString::from_vec(buf))
775}
776
777#[cfg(all(target_vendor = "apple", not(miri)))]
778fn darwin_temp_dir() -> PathBuf {
779 confstr(libc::_CS_DARWIN_USER_TEMP_DIR, Some(64)).map(PathBuf::from).unwrap_or_else(|_| {
780 PathBuf::from("/tmp")
783 })
784}
785
786pub fn temp_dir() -> PathBuf {
787 crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
788 cfg_if::cfg_if! {
789 if #[cfg(all(target_vendor = "apple", not(miri)))] {
790 darwin_temp_dir()
791 } else if #[cfg(target_os = "android")] {
792 PathBuf::from("/data/local/tmp")
793 } else {
794 PathBuf::from("/tmp")
795 }
796 }
797 })
798}
799
800pub fn home_dir() -> Option<PathBuf> {
801 return crate::env::var_os("HOME").or_else(|| unsafe { fallback() }).map(PathBuf::from);
802
803 #[cfg(any(
804 target_os = "android",
805 target_os = "emscripten",
806 target_os = "redox",
807 target_os = "vxworks",
808 target_os = "espidf",
809 target_os = "horizon",
810 target_os = "vita",
811 target_os = "nuttx",
812 all(target_vendor = "apple", not(target_os = "macos")),
813 ))]
814 unsafe fn fallback() -> Option<OsString> {
815 None
816 }
817 #[cfg(not(any(
818 target_os = "android",
819 target_os = "emscripten",
820 target_os = "redox",
821 target_os = "vxworks",
822 target_os = "espidf",
823 target_os = "horizon",
824 target_os = "vita",
825 target_os = "nuttx",
826 all(target_vendor = "apple", not(target_os = "macos")),
827 )))]
828 unsafe fn fallback() -> Option<OsString> {
829 let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
830 n if n < 0 => 512 as usize,
831 n => n as usize,
832 };
833 let mut buf = Vec::with_capacity(amt);
834 let mut p = mem::MaybeUninit::<libc::passwd>::uninit();
835 let mut result = ptr::null_mut();
836 match libc::getpwuid_r(
837 libc::getuid(),
838 p.as_mut_ptr(),
839 buf.as_mut_ptr(),
840 buf.capacity(),
841 &mut result,
842 ) {
843 0 if !result.is_null() => {
844 let ptr = (*result).pw_dir as *const _;
845 let bytes = CStr::from_ptr(ptr).to_bytes().to_vec();
846 Some(OsStringExt::from_vec(bytes))
847 }
848 _ => None,
849 }
850 }
851}
852
853pub fn exit(code: i32) -> ! {
854 crate::sys::exit_guard::unique_thread_exit();
855 unsafe { libc::exit(code as c_int) }
856}
857
858pub fn getpid() -> u32 {
859 unsafe { libc::getpid() as u32 }
860}
861
862pub fn getppid() -> u32 {
863 unsafe { libc::getppid() as u32 }
864}
865
866#[cfg(all(target_os = "linux", target_env = "gnu"))]
867pub fn glibc_version() -> Option<(usize, usize)> {
868 unsafe extern "C" {
869 fn gnu_get_libc_version() -> *const libc::c_char;
870 }
871 let version_cstr = unsafe { CStr::from_ptr(gnu_get_libc_version()) };
872 if let Ok(version_str) = version_cstr.to_str() {
873 parse_glibc_version(version_str)
874 } else {
875 None
876 }
877}
878
879#[cfg(all(target_os = "linux", target_env = "gnu"))]
882fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
883 let mut parsed_ints = version.split('.').map(str::parse::<usize>).fuse();
884 match (parsed_ints.next(), parsed_ints.next()) {
885 (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)),
886 _ => None,
887 }
888}