1//! Uname support.
2//!
3//! # Safety
4//!
5//! This function converts from `struct utsname` fields provided from the
6//! kernel into `&str` references, which assumes that they're NUL-terminated.
7#![allow(unsafe_code)]
8
9use crate::backend;
10use crate::ffi::CStr;
11use core::fmt;
12
13/// `uname()`—Returns high-level information about the runtime OS and
14/// hardware.
15#[inline]
16pub fn uname() -> Uname {
17    Uname(backend::process::syscalls::uname())
18}
19
20/// `struct utsname`—Return type for [`uname`].
21#[doc(alias = "utsname")]
22pub struct Uname(backend::process::types::RawUname);
23
24impl Uname {
25    /// `sysname`—Operating system release name
26    #[inline]
27    pub fn sysname(&self) -> &CStr {
28        Self::to_cstr(self.0.sysname.as_ptr().cast())
29    }
30
31    /// `nodename`—Name with vague meaning
32    ///
33    /// This is intended to be a network name, however it's unable to convey
34    /// information about hosts that have multiple names, or any information
35    /// about where the names are visible.
36    #[inline]
37    pub fn nodename(&self) -> &CStr {
38        Self::to_cstr(self.0.nodename.as_ptr().cast())
39    }
40
41    /// `release`—Operating system release version string
42    #[inline]
43    pub fn release(&self) -> &CStr {
44        Self::to_cstr(self.0.release.as_ptr().cast())
45    }
46
47    /// `version`—Operating system build identifiers
48    #[inline]
49    pub fn version(&self) -> &CStr {
50        Self::to_cstr(self.0.version.as_ptr().cast())
51    }
52
53    /// `machine`—Hardware architecture identifier
54    #[inline]
55    pub fn machine(&self) -> &CStr {
56        Self::to_cstr(self.0.machine.as_ptr().cast())
57    }
58
59    /// `domainname`—NIS or YP domain identifier
60    #[cfg(any(target_os = "android", target_os = "linux"))]
61    #[inline]
62    pub fn domainname(&self) -> &CStr {
63        Self::to_cstr(self.0.domainname.as_ptr().cast())
64    }
65
66    #[inline]
67    fn to_cstr<'a>(ptr: *const u8) -> &'a CStr {
68        // Safety: Strings returned from the kernel are always NUL-terminated.
69        unsafe { CStr::from_ptr(ptr.cast()) }
70    }
71}
72
73impl fmt::Debug for Uname {
74    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
75        #[cfg(not(any(target_os = "android", target_os = "linux")))]
76        {
77            write!(
78                fmt,
79                "{} {} {} {} {}",
80                self.sysname().to_string_lossy(),
81                self.nodename().to_string_lossy(),
82                self.release().to_string_lossy(),
83                self.version().to_string_lossy(),
84                self.machine().to_string_lossy(),
85            )
86        }
87        #[cfg(any(target_os = "android", target_os = "linux"))]
88        {
89            write!(
90                fmt,
91                "{} {} {} {} {} {}",
92                self.sysname().to_string_lossy(),
93                self.nodename().to_string_lossy(),
94                self.release().to_string_lossy(),
95                self.version().to_string_lossy(),
96                self.machine().to_string_lossy(),
97                self.domainname().to_string_lossy(),
98            )
99        }
100    }
101}
102