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