| 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/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§ion=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 ] |
| 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, 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 ] |
| 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 | /// `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 ] |
| 190 | pub 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 ] |
| 199 | pub 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" )] |
| 246 | pub 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)] |
| 258 | pub 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)] |
| 270 | pub 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)] |
| 282 | pub fn delete_module(name: &CStr, flags: c_int) -> io::Result<()> { |
| 283 | backend::system::syscalls::delete_module(name, flags) |
| 284 | } |
| 285 | |