Skip to main content

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