rustix/
system.rs

1//! Uname and other system-level functions.
2
3#![allow(unsafe_code)]
4
5use crate::backend;
6#[cfg(target_os = "linux")]
7use crate::backend::c;
8use crate::ffi::CStr;
9#[cfg(not(any(target_os = "espidf", target_os = "emscripten", target_os = "vita")))]
10use crate::io;
11use core::fmt;
12
13#[cfg(linux_kernel)]
14pub use backend::system::types::Sysinfo;
15
16#[cfg(linux_kernel)]
17use crate::fd::AsFd;
18#[cfg(linux_kernel)]
19use crate::ffi::c_int;
20
21/// `uname()`—Returns high-level information about the runtime OS and
22/// hardware.
23///
24/// For `gethostname()`, use [`Uname::nodename`] on the result.
25///
26/// # References
27///  - [POSIX]
28///  - [Linux]
29///  - [Apple]
30///  - [NetBSD]
31///  - [FreeBSD]
32///  - [OpenBSD]
33///  - [DragonFly BSD]
34///  - [illumos]
35///  - [glibc]
36///
37/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/uname.html
38/// [Linux]: https://man7.org/linux/man-pages/man2/uname.2.html
39/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/uname.3.html
40/// [NetBSD]: https://man.netbsd.org/uname.3
41/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=uname&sektion=3
42/// [OpenBSD]: https://man.openbsd.org/uname.3
43/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=uname&section=3
44/// [illumos]: https://illumos.org/man/2/uname
45/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Platform-Type.html
46#[doc(alias = "gethostname")]
47#[inline]
48pub fn uname() -> Uname {
49    Uname(backend::system::syscalls::uname())
50}
51
52/// `struct utsname`—Return type for [`uname`].
53#[doc(alias = "utsname")]
54pub struct Uname(backend::system::types::RawUname);
55
56impl Uname {
57    /// `sysname`—Operating system release name.
58    #[inline]
59    pub fn sysname(&self) -> &CStr {
60        Self::to_cstr(self.0.sysname.as_ptr().cast())
61    }
62
63    /// `nodename`—Name with vague meaning.
64    ///
65    /// This is intended to be a network name, however it's unable to convey
66    /// information about hosts that have multiple names, or any information
67    /// about where the names are visible.
68    ///
69    /// This corresponds to the `gethostname` value.
70    #[inline]
71    pub fn nodename(&self) -> &CStr {
72        Self::to_cstr(self.0.nodename.as_ptr().cast())
73    }
74
75    /// `release`—Operating system release version string.
76    #[inline]
77    pub fn release(&self) -> &CStr {
78        Self::to_cstr(self.0.release.as_ptr().cast())
79    }
80
81    /// `version`—Operating system build identifiers.
82    #[inline]
83    pub fn version(&self) -> &CStr {
84        Self::to_cstr(self.0.version.as_ptr().cast())
85    }
86
87    /// `machine`—Hardware architecture identifier.
88    #[inline]
89    pub fn machine(&self) -> &CStr {
90        Self::to_cstr(self.0.machine.as_ptr().cast())
91    }
92
93    /// `domainname`—NIS or YP domain identifier.
94    #[cfg(linux_kernel)]
95    #[inline]
96    pub fn domainname(&self) -> &CStr {
97        Self::to_cstr(self.0.domainname.as_ptr().cast())
98    }
99
100    #[inline]
101    fn to_cstr<'a>(ptr: *const u8) -> &'a CStr {
102        // SAFETY: Strings returned from the kernel are always NUL-terminated.
103        unsafe { CStr::from_ptr(ptr.cast()) }
104    }
105}
106
107impl fmt::Debug for Uname {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        #[cfg(not(linux_kernel))]
110        {
111            write!(
112                f,
113                "{:?} {:?} {:?} {:?} {:?}",
114                self.sysname(),
115                self.nodename(),
116                self.release(),
117                self.version(),
118                self.machine(),
119            )
120        }
121        #[cfg(linux_kernel)]
122        {
123            write!(
124                f,
125                "{:?} {:?} {:?} {:?} {:?} {:?}",
126                self.sysname(),
127                self.nodename(),
128                self.release(),
129                self.version(),
130                self.machine(),
131                self.domainname(),
132            )
133        }
134    }
135}
136
137/// `sysinfo()`—Returns status information about the runtime OS.
138///
139/// # References
140///  - [Linux]
141///
142/// [Linux]: https://man7.org/linux/man-pages/man2/uname.2.html
143#[cfg(linux_kernel)]
144#[inline]
145pub fn sysinfo() -> Sysinfo {
146    backend::system::syscalls::sysinfo()
147}
148
149/// `sethostname(name)`—Sets the system host name.
150///
151/// # References
152///  - [Linux]
153///
154/// [Linux]: https://man7.org/linux/man-pages/man2/sethostname.2.html
155#[cfg(not(any(
156    target_os = "emscripten",
157    target_os = "espidf",
158    target_os = "horizon",
159    target_os = "redox",
160    target_os = "vita",
161    target_os = "wasi"
162)))]
163#[inline]
164pub fn sethostname(name: &[u8]) -> io::Result<()> {
165    backend::system::syscalls::sethostname(name)
166}
167
168/// `setdomain(name)`—Sets the system NIS domain name.
169///
170/// # References
171///  - [Linux]
172///  - [FreeBSD]
173///
174/// [Linux]: https://man7.org/linux/man-pages/man2/setdomainname.2.html
175/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=setdomainname&sektion=3
176#[cfg(not(any(
177    target_os = "cygwin",
178    target_os = "emscripten",
179    target_os = "espidf",
180    target_os = "haiku",
181    target_os = "horizon",
182    target_os = "illumos",
183    target_os = "redox",
184    target_os = "solaris",
185    target_os = "vita",
186    target_os = "wasi",
187)))]
188#[inline]
189pub fn setdomainname(name: &[u8]) -> io::Result<()> {
190    backend::system::syscalls::setdomainname(name)
191}
192
193/// Reboot command for use with [`reboot`].
194#[cfg(target_os = "linux")]
195#[derive(Copy, Clone, Debug, Eq, PartialEq)]
196#[repr(i32)]
197#[non_exhaustive]
198pub enum RebootCommand {
199    /// Disables the Ctrl-Alt-Del keystroke.
200    ///
201    /// When disabled, the keystroke will send a [`Signal::INT`] to
202    /// [`Pid::INIT`].
203    ///
204    /// [`Signal::INT`]: crate::process::Signal::INT
205    /// [`Pid::INIT`]: crate::process::Pid::INIT
206    CadOff = c::LINUX_REBOOT_CMD_CAD_OFF,
207    /// Enables the Ctrl-Alt-Del keystroke.
208    ///
209    /// When enabled, the keystroke will trigger a [`Restart`].
210    ///
211    /// [`Restart`]: Self::Restart
212    CadOn = c::LINUX_REBOOT_CMD_CAD_ON,
213    /// Prints the message "System halted" and halts the system
214    Halt = c::LINUX_REBOOT_CMD_HALT,
215    /// Execute a kernel that has been loaded earlier with [`kexec_load`].
216    ///
217    /// [`kexec_load`]: https://man7.org/linux/man-pages/man2/kexec_load.2.html
218    Kexec = c::LINUX_REBOOT_CMD_KEXEC,
219    /// Prints the message "Power down.", stops the system, and tries to remove
220    /// all power
221    PowerOff = c::LINUX_REBOOT_CMD_POWER_OFF,
222    /// Prints the message "Restarting system." and triggers a restart
223    Restart = c::LINUX_REBOOT_CMD_RESTART,
224    /// Hibernate the system by suspending to disk
225    SwSuspend = c::LINUX_REBOOT_CMD_SW_SUSPEND,
226}
227
228/// `reboot`—Reboot the system or enable/disable Ctrl-Alt-Del.
229///
230/// The reboot syscall, despite the name, can actually do much more than
231/// reboot.
232///
233/// Among other things, it can:
234///  - Restart, Halt, Power Off, and Suspend the system
235///  - Enable and disable the Ctrl-Alt-Del keystroke
236///  - Execute other kernels
237///  - Terminate init inside PID namespaces
238///
239/// It is highly recommended to carefully read the kernel documentation before
240/// calling this function.
241///
242/// # References
243///  - [Linux]
244///
245/// [Linux]: https://man7.org/linux/man-pages/man2/reboot.2.html
246#[cfg(target_os = "linux")]
247pub fn reboot(cmd: RebootCommand) -> io::Result<()> {
248    backend::system::syscalls::reboot(cmd)
249}
250
251/// `init_module`—Load a kernel module.
252///
253/// # References
254///  - [Linux]
255///
256/// [Linux]: https://man7.org/linux/man-pages/man2/init_module.2.html
257#[inline]
258#[cfg(linux_kernel)]
259pub fn init_module(image: &[u8], param_values: &CStr) -> io::Result<()> {
260    backend::system::syscalls::init_module(image, param_values)
261}
262
263/// `finit_module`—Load a kernel module from a file descriptor.
264///
265/// # References
266///  - [Linux]
267///
268/// [Linux]: https://man7.org/linux/man-pages/man2/finit_module.2.html
269#[inline]
270#[cfg(linux_kernel)]
271pub fn finit_module<Fd: AsFd>(fd: Fd, param_values: &CStr, flags: c_int) -> io::Result<()> {
272    backend::system::syscalls::finit_module(fd.as_fd(), param_values, flags)
273}
274
275/// `delete_module`—Unload a kernel module.
276///
277/// # References
278///  - [Linux]
279///
280/// [Linux]: https://man7.org/linux/man-pages/man2/delete_module.2.html
281#[inline]
282#[cfg(linux_kernel)]
283pub fn delete_module(name: &CStr, flags: c_int) -> io::Result<()> {
284    backend::system::syscalls::delete_module(name, flags)
285}
286
287#[cfg(test)]
288mod tests {
289    #[allow(unused_imports)]
290    use super::*;
291    #[allow(unused_imports)]
292    use crate::backend::c;
293
294    #[cfg(linux_kernel)]
295    #[test]
296    fn test_sysinfo_layouts() {
297        // Don't assert the size for `Sysinfo` because `c::sysinfo` has a
298        // computed-size padding field at the end that bindgen doesn't support,
299        // and `c::sysinfo` may add fields over time.
300        assert_eq!(
301            core::mem::align_of::<Sysinfo>(),
302            core::mem::align_of::<c::sysinfo>()
303        );
304        check_renamed_struct_field!(Sysinfo, sysinfo, uptime);
305        check_renamed_struct_field!(Sysinfo, sysinfo, loads);
306        check_renamed_struct_field!(Sysinfo, sysinfo, totalram);
307        check_renamed_struct_field!(Sysinfo, sysinfo, freeram);
308        check_renamed_struct_field!(Sysinfo, sysinfo, sharedram);
309        check_renamed_struct_field!(Sysinfo, sysinfo, bufferram);
310        check_renamed_struct_field!(Sysinfo, sysinfo, totalswap);
311        check_renamed_struct_field!(Sysinfo, sysinfo, freeswap);
312        check_renamed_struct_field!(Sysinfo, sysinfo, procs);
313        check_renamed_struct_field!(Sysinfo, sysinfo, totalhigh);
314        check_renamed_struct_field!(Sysinfo, sysinfo, freehigh);
315        check_renamed_struct_field!(Sysinfo, sysinfo, mem_unit);
316    }
317}