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 (linux_kernel)] |
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 | #[cfg (linux_kernel)] |
21 | use crate::fd::AsFd; |
22 | #[cfg (linux_kernel)] |
23 | use 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/9699919799/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§ion=3 |
48 | /// [illumos]: https://illumos.org/man/2/uname |
49 | /// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Platform-Type.html |
50 | #[doc (alias = "gethostname" )] |
51 | #[inline ] |
52 | pub fn uname() -> Uname { |
53 | Uname(backend::system::syscalls::uname()) |
54 | } |
55 | |
56 | /// `struct utsname`—Return type for [`uname`]. |
57 | #[doc (alias = "utsname" )] |
58 | pub struct Uname(backend::system::types::RawUname); |
59 | |
60 | impl 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 | |
111 | impl fmt::Debug for Uname { |
112 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
113 | #[cfg (not(linux_kernel))] |
114 | { |
115 | write!( |
116 | fmt, |
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 | fmt, |
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 ] |
149 | pub 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 ] |
167 | pub fn sethostname(name: &[u8]) -> io::Result<()> { |
168 | backend::system::syscalls::sethostname(name) |
169 | } |
170 | |
171 | /// Reboot command for use with [`reboot`]. |
172 | #[cfg (target_os = "linux" )] |
173 | #[derive (Copy, Clone, Debug, Eq, PartialEq)] |
174 | #[repr (i32)] |
175 | #[non_exhaustive ] |
176 | pub enum RebootCommand { |
177 | /// Disables the Ctrl-Alt-Del keystroke. |
178 | /// |
179 | /// When disabled, the keystroke will send a [`Signal::Int`] to pid 1. |
180 | /// |
181 | /// [`Signal::Int`]: crate::process::Signal::Int |
182 | CadOff = c::LINUX_REBOOT_CMD_CAD_OFF, |
183 | /// Enables the Ctrl-Alt-Del keystroke. |
184 | /// |
185 | /// When enabled, the keystroke will trigger a [`Restart`]. |
186 | /// |
187 | /// [`Restart`]: Self::Restart |
188 | CadOn = c::LINUX_REBOOT_CMD_CAD_ON, |
189 | /// Prints the message "System halted" and halts the system |
190 | Halt = c::LINUX_REBOOT_CMD_HALT, |
191 | /// Execute a kernel that has been loaded earlier with [`kexec_load`]. |
192 | /// |
193 | /// [`kexec_load`]: https://man7.org/linux/man-pages/man2/kexec_load.2.html |
194 | Kexec = c::LINUX_REBOOT_CMD_KEXEC, |
195 | /// Prints the message "Power down.", stops the system, and tries to remove |
196 | /// all power |
197 | PowerOff = c::LINUX_REBOOT_CMD_POWER_OFF, |
198 | /// Prints the message "Restarting system." and triggers a restart |
199 | Restart = c::LINUX_REBOOT_CMD_RESTART, |
200 | /// Hibernate the system by suspending to disk |
201 | SwSuspend = c::LINUX_REBOOT_CMD_SW_SUSPEND, |
202 | } |
203 | |
204 | /// `reboot`—Reboot the system or enable/disable Ctrl-Alt-Del |
205 | /// |
206 | /// The reboot syscall, despite the name, can actually do much more than |
207 | /// reboot. |
208 | /// |
209 | /// Among other things, it can: |
210 | /// - Restart, Halt, Power Off, and Suspend the system |
211 | /// - Enable and disable the Ctrl-Alt-Del keystroke |
212 | /// - Execute other kernels |
213 | /// - Terminate init inside PID namespaces |
214 | /// |
215 | /// It is highly recommended to carefully read the kernel documentation before |
216 | /// calling this function. |
217 | /// |
218 | /// # References |
219 | /// - [Linux] |
220 | /// |
221 | /// [Linux]: https://man7.org/linux/man-pages/man2/reboot.2.html |
222 | #[cfg (target_os = "linux" )] |
223 | pub fn reboot(cmd: RebootCommand) -> io::Result<()> { |
224 | backend::system::syscalls::reboot(cmd) |
225 | } |
226 | |
227 | /// `init_module`—Load a kernel module |
228 | /// |
229 | /// # References |
230 | /// - [Linux] |
231 | /// |
232 | /// [Linux]: https://man7.org/linux/man-pages/man2/init_module.2.html |
233 | #[inline ] |
234 | #[cfg (linux_kernel)] |
235 | pub fn init_module(image: &[u8], param_values: &CStr) -> io::Result<()> { |
236 | backend::system::syscalls::init_module(image, param_values) |
237 | } |
238 | |
239 | /// `finit_module`—Load a kernel module from a file descriptor |
240 | /// |
241 | /// # References |
242 | /// - [Linux] |
243 | /// |
244 | /// [Linux]: https://man7.org/linux/man-pages/man2/finit_module.2.html |
245 | #[inline ] |
246 | #[cfg (linux_kernel)] |
247 | pub fn finit_module<Fd: AsFd>(fd: Fd, param_values: &CStr, flags: c_int) -> io::Result<()> { |
248 | backend::system::syscalls::finit_module(fd.as_fd(), param_values, flags) |
249 | } |
250 | |
251 | /// `delete_module`—Unload a kernel module |
252 | /// |
253 | /// # References |
254 | /// - [Linux] |
255 | /// |
256 | /// [Linux]: https://man7.org/linux/man-pages/man2/delete_module.2.html |
257 | #[inline ] |
258 | #[cfg (linux_kernel)] |
259 | pub fn delete_module(name: &CStr, flags: c_int) -> io::Result<()> { |
260 | backend::system::syscalls::delete_module(name, flags) |
261 | } |
262 | |