rustix/
system.rs

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