1 //! `rustix` provides efficient memory-safe and [I/O-safe] wrappers to 2 //! POSIX-like, Unix-like, Linux, and Winsock syscall-like APIs, with 3 //! configurable backends. 4 //! 5 //! With rustix, you can write code like this: 6 //! 7 //! ``` 8 //! # #[cfg(feature = "net")] 9 //! # fn read(sock: std::net::TcpStream, buf: &mut [u8]) -> std::io::Result<()> { 10 //! # use rustix::net::RecvFlags; 11 //! let nread: usize = rustix::net::recv(&sock, buf, RecvFlags::PEEK)?; 12 //! # let _ = nread; 13 //! # Ok(()) 14 //! # } 15 //! ``` 16 //! 17 //! instead of like this: 18 //! 19 //! ``` 20 //! # #[cfg(feature = "net")] 21 //! # fn read(sock: std::net::TcpStream, buf: &mut [u8]) -> std::io::Result<()> { 22 //! # #[cfg(unix)] 23 //! # use std::os::unix::io::AsRawFd; 24 //! # #[cfg(target_os = "wasi")] 25 //! # use std::os::wasi::io::AsRawFd; 26 //! # #[cfg(windows)] 27 //! # use windows_sys::Win32::Networking::WinSock as libc; 28 //! # #[cfg(windows)] 29 //! # use std::os::windows::io::AsRawSocket; 30 //! # const MSG_PEEK: i32 = libc::MSG_PEEK; 31 //! let nread: usize = unsafe { 32 //! #[cfg(any(unix, target_os = "wasi"))] 33 //! let raw = sock.as_raw_fd(); 34 //! #[cfg(windows)] 35 //! let raw = sock.as_raw_socket(); 36 //! match libc::recv( 37 //! raw as _, 38 //! buf.as_mut_ptr().cast(), 39 //! buf.len().try_into().unwrap_or(i32::MAX as _), 40 //! MSG_PEEK, 41 //! ) { 42 //! -1 => return Err(std::io::Error::last_os_error()), 43 //! nread => nread as usize, 44 //! } 45 //! }; 46 //! # let _ = nread; 47 //! # Ok(()) 48 //! # } 49 //! ``` 50 //! 51 //! rustix's APIs perform the following tasks: 52 //! - Error values are translated to [`Result`]s. 53 //! - Buffers are passed as Rust slices. 54 //! - Out-parameters are presented as return values. 55 //! - Path arguments use [`Arg`], so they accept any string type. 56 //! - File descriptors are passed and returned via [`AsFd`] and [`OwnedFd`] 57 //! instead of bare integers, ensuring I/O safety. 58 //! - Constants use `enum`s and [`bitflags`] types, and enable [support for 59 //! externally defined flags]. 60 //! - Multiplexed functions (eg. `fcntl`, `ioctl`, etc.) are de-multiplexed. 61 //! - Variadic functions (eg. `openat`, etc.) are presented as non-variadic. 62 //! - Functions that return strings automatically allocate sufficient memory 63 //! and retry the syscall as needed to determine the needed length. 64 //! - Functions and types which need `l` prefixes or `64` suffixes to enable 65 //! large-file support (LFS) are used automatically. File sizes and offsets 66 //! are always presented as `u64` and `i64`. 67 //! - Behaviors that depend on the sizes of C types like `long` are hidden. 68 //! - In some places, more human-friendly and less historical-accident names 69 //! are used (and documentation aliases are used so that the original names 70 //! can still be searched for). 71 //! - Provide y2038 compatibility, on platforms which support this. 72 //! - Correct selected platform bugs, such as behavioral differences when 73 //! running under seccomp. 74 //! 75 //! Things they don't do include: 76 //! - Detecting whether functions are supported at runtime, except in specific 77 //! cases where new interfaces need to be detected to support y2038 and LFS. 78 //! - Hiding significant differences between platforms. 79 //! - Restricting ambient authorities. 80 //! - Imposing sandboxing features such as filesystem path or network address 81 //! sandboxing. 82 //! 83 //! See [`cap-std`], [`system-interface`], and [`io-streams`] for libraries 84 //! which do hide significant differences between platforms, and [`cap-std`] 85 //! which does perform sandboxing and restricts ambient authorities. 86 //! 87 //! [`cap-std`]: https://crates.io/crates/cap-std 88 //! [`system-interface`]: https://crates.io/crates/system-interface 89 //! [`io-streams`]: https://crates.io/crates/io-streams 90 //! [`getrandom`]: https://crates.io/crates/getrandom 91 //! [`bitflags`]: https://crates.io/crates/bitflags 92 //! [`AsFd`]: https://doc.rust-lang.org/stable/std/os/fd/trait.AsFd.html 93 //! [`OwnedFd`]: https://doc.rust-lang.org/stable/std/os/fd/struct.OwnedFd.html 94 //! [I/O-safe]: https://github.com/rust-lang/rfcs/blob/master/text/3128-io-safety.md 95 //! [`Result`]: https://doc.rust-lang.org/stable/std/result/enum.Result.html 96 //! [`Arg`]: https://docs.rs/rustix/*/rustix/path/trait.Arg.html 97 //! [support for externally defined flags]: https://docs.rs/bitflags/*/bitflags/#externally-defined-flags 98 99 #![deny(missing_docs)] 100 #![allow(stable_features)] 101 #![cfg_attr(linux_raw, deny(unsafe_code))] 102 #![cfg_attr(rustc_attrs, feature(rustc_attrs))] 103 #![cfg_attr(doc_cfg, feature(doc_cfg))] 104 #![cfg_attr(all(wasi_ext, target_os = "wasi", feature = "std"), feature(wasi_ext))] 105 #![cfg_attr(core_ffi_c, feature(core_ffi_c))] 106 #![cfg_attr(core_c_str, feature(core_c_str))] 107 #![cfg_attr(all(feature = "alloc", alloc_c_string), feature(alloc_c_string))] 108 #![cfg_attr(all(feature = "alloc", alloc_ffi), feature(alloc_ffi))] 109 #![cfg_attr(not(feature = "std"), no_std)] 110 #![cfg_attr(feature = "rustc-dep-of-std", feature(ip))] 111 #![cfg_attr(feature = "rustc-dep-of-std", allow(internal_features))] 112 #![cfg_attr( 113 any(feature = "rustc-dep-of-std", core_intrinsics), 114 feature(core_intrinsics) 115 )] 116 #![cfg_attr(asm_experimental_arch, feature(asm_experimental_arch))] 117 #![cfg_attr(not(feature = "all-apis"), allow(dead_code))] 118 // It is common in Linux and libc APIs for types to vary between platforms. 119 #![allow(clippy::unnecessary_cast)] 120 // It is common in Linux and libc APIs for types to vary between platforms. 121 #![allow(clippy::useless_conversion)] 122 // Redox and WASI have enough differences that it isn't worth precisely 123 // conditionalizing all the `use`s for them. Similar for if we don't have 124 // "all-apis". 125 #![cfg_attr( 126 any(target_os = "redox", target_os = "wasi", not(feature = "all-apis")), 127 allow(unused_imports) 128 )] 129 130 #[cfg(all(feature = "alloc", not(feature = "rustc-dep-of-std")))] 131 extern crate alloc; 132 133 // Use `static_assertions` macros if we have them, or a polyfill otherwise. 134 #[cfg(all(test, static_assertions))] 135 #[macro_use] 136 #[allow(unused_imports)] 137 extern crate static_assertions; 138 #[cfg(all(test, not(static_assertions)))] 139 #[macro_use] 140 #[allow(unused_imports)] 141 mod static_assertions; 142 143 // Internal utilities. 144 mod buffer; 145 #[cfg(not(windows))] 146 #[macro_use] 147 pub(crate) mod cstr; 148 #[macro_use] 149 pub(crate) mod utils; 150 // Polyfill for `std` in `no_std` builds. 151 #[cfg_attr(feature = "std", path = "maybe_polyfill/std/mod.rs")] 152 #[cfg_attr(not(feature = "std"), path = "maybe_polyfill/no_std/mod.rs")] 153 pub(crate) mod maybe_polyfill; 154 #[cfg(test)] 155 #[macro_use] 156 pub(crate) mod check_types; 157 #[macro_use] 158 pub(crate) mod bitcast; 159 160 // linux_raw: Weak symbols are used by the use-libc-auxv feature for 161 // glibc 2.15 support. 162 // 163 // libc: Weak symbols are used to call various functions available in some 164 // versions of libc and not others. 165 #[cfg(any( 166 all(linux_raw, feature = "use-libc-auxv"), 167 all(libc, not(any(windows, target_os = "espidf", target_os = "wasi"))) 168 ))] 169 #[macro_use] 170 mod weak; 171 172 // Pick the backend implementation to use. 173 #[cfg_attr(libc, path = "backend/libc/mod.rs")] 174 #[cfg_attr(linux_raw, path = "backend/linux_raw/mod.rs")] 175 #[cfg_attr(wasi, path = "backend/wasi/mod.rs")] 176 mod backend; 177 178 /// Export the `*Fd` types and traits that are used in rustix's public API. 179 /// 180 /// Users can use this to avoid needing to import anything else to use the same 181 /// versions of these types and traits. 182 pub mod fd { 183 use super::backend; 184 185 // Re-export `AsSocket` etc. too, as users can't implement `AsFd` etc. on 186 // Windows due to them having blanket impls on Windows, so users must 187 // implement `AsSocket` etc. 188 #[cfg(windows)] 189 pub use backend::fd::{AsRawSocket, AsSocket, FromRawSocket, IntoRawSocket}; 190 191 pub use backend::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; 192 } 193 194 // The public API modules. 195 #[cfg(feature = "event")] 196 #[cfg_attr(doc_cfg, doc(cfg(feature = "event")))] 197 pub mod event; 198 #[cfg(not(windows))] 199 pub mod ffi; 200 #[cfg(not(windows))] 201 #[cfg(feature = "fs")] 202 #[cfg_attr(doc_cfg, doc(cfg(feature = "fs")))] 203 pub mod fs; 204 pub mod io; 205 #[cfg(linux_kernel)] 206 #[cfg(feature = "io_uring")] 207 #[cfg_attr(doc_cfg, doc(cfg(feature = "io_uring")))] 208 pub mod io_uring; 209 pub mod ioctl; 210 #[cfg(not(any(windows, target_os = "espidf", target_os = "vita", target_os = "wasi")))] 211 #[cfg(feature = "mm")] 212 #[cfg_attr(doc_cfg, doc(cfg(feature = "mm")))] 213 pub mod mm; 214 #[cfg(linux_kernel)] 215 #[cfg(feature = "mount")] 216 #[cfg_attr(doc_cfg, doc(cfg(feature = "mount")))] 217 pub mod mount; 218 #[cfg(not(any(target_os = "redox", target_os = "wasi")))] 219 #[cfg(feature = "net")] 220 #[cfg_attr(doc_cfg, doc(cfg(feature = "net")))] 221 pub mod net; 222 #[cfg(not(any(windows, target_os = "espidf")))] 223 #[cfg(feature = "param")] 224 #[cfg_attr(doc_cfg, doc(cfg(feature = "param")))] 225 pub mod param; 226 #[cfg(not(windows))] 227 #[cfg(any(feature = "fs", feature = "mount", feature = "net"))] 228 #[cfg_attr( 229 doc_cfg, 230 doc(cfg(any(feature = "fs", feature = "mount", feature = "net"))) 231 )] 232 pub mod path; 233 #[cfg(feature = "pipe")] 234 #[cfg_attr(doc_cfg, doc(cfg(feature = "pipe")))] 235 #[cfg(not(any(windows, target_os = "wasi")))] 236 pub mod pipe; 237 #[cfg(not(windows))] 238 #[cfg(feature = "process")] 239 #[cfg_attr(doc_cfg, doc(cfg(feature = "process")))] 240 pub mod process; 241 #[cfg(feature = "procfs")] 242 #[cfg(linux_kernel)] 243 #[cfg_attr(doc_cfg, doc(cfg(feature = "procfs")))] 244 pub mod procfs; 245 #[cfg(not(windows))] 246 #[cfg(not(target_os = "wasi"))] 247 #[cfg(feature = "pty")] 248 #[cfg_attr(doc_cfg, doc(cfg(feature = "pty")))] 249 pub mod pty; 250 #[cfg(not(windows))] 251 #[cfg(feature = "rand")] 252 #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))] 253 pub mod rand; 254 #[cfg(not(any( 255 windows, 256 target_os = "android", 257 target_os = "espidf", 258 target_os = "vita", 259 target_os = "wasi" 260 )))] 261 #[cfg(feature = "shm")] 262 #[cfg_attr(doc_cfg, doc(cfg(feature = "shm")))] 263 pub mod shm; 264 #[cfg(not(windows))] 265 #[cfg(feature = "stdio")] 266 #[cfg_attr(doc_cfg, doc(cfg(feature = "stdio")))] 267 pub mod stdio; 268 #[cfg(feature = "system")] 269 #[cfg(not(any(windows, target_os = "wasi")))] 270 #[cfg_attr(doc_cfg, doc(cfg(feature = "system")))] 271 pub mod system; 272 #[cfg(not(any(windows, target_os = "vita")))] 273 #[cfg(feature = "termios")] 274 #[cfg_attr(doc_cfg, doc(cfg(feature = "termios")))] 275 pub mod termios; 276 #[cfg(not(windows))] 277 #[cfg(feature = "thread")] 278 #[cfg_attr(doc_cfg, doc(cfg(feature = "thread")))] 279 pub mod thread; 280 #[cfg(not(any(windows, target_os = "espidf")))] 281 #[cfg(feature = "time")] 282 #[cfg_attr(doc_cfg, doc(cfg(feature = "time")))] 283 pub mod time; 284 285 // "runtime" is also a public API module, but it's only for libc-like users. 286 #[cfg(not(windows))] 287 #[cfg(feature = "runtime")] 288 #[cfg(linux_raw)] 289 #[cfg_attr(not(document_experimental_runtime_api), doc(hidden))] 290 #[cfg_attr(doc_cfg, doc(cfg(feature = "runtime")))] 291 pub mod runtime; 292 293 // Temporarily provide some mount functions for use in the fs module for 294 // backwards compatibility. 295 #[cfg(linux_kernel)] 296 #[cfg(all(feature = "fs", not(feature = "mount")))] 297 pub(crate) mod mount; 298 299 // Declare "fs" as a non-public module if "fs" isn't enabled but we need it for 300 // reading procfs. 301 #[cfg(not(windows))] 302 #[cfg(not(feature = "fs"))] 303 #[cfg(all( 304 linux_raw, 305 not(feature = "use-libc-auxv"), 306 not(feature = "use-explicitly-provided-auxv"), 307 any( 308 feature = "param", 309 feature = "process", 310 feature = "runtime", 311 feature = "time", 312 target_arch = "x86", 313 ) 314 ))] 315 #[cfg_attr(doc_cfg, doc(cfg(feature = "fs")))] 316 pub(crate) mod fs; 317 318 // Similarly, declare `path` as a non-public module if needed. 319 #[cfg(not(windows))] 320 #[cfg(not(any(feature = "fs", feature = "mount", feature = "net")))] 321 #[cfg(all( 322 linux_raw, 323 not(feature = "use-libc-auxv"), 324 not(feature = "use-explicitly-provided-auxv"), 325 any( 326 feature = "param", 327 feature = "process", 328 feature = "runtime", 329 feature = "time", 330 target_arch = "x86", 331 ) 332 ))] 333 pub(crate) mod path; 334 335 // Private modules used by multiple public modules. 336 #[cfg(not(any(windows, target_os = "espidf")))] 337 #[cfg(any(feature = "thread", feature = "time", target_arch = "x86"))] 338 mod clockid; 339 #[cfg(not(any(windows, target_os = "wasi")))] 340 #[cfg(any( 341 feature = "procfs", 342 feature = "process", 343 feature = "runtime", 344 feature = "termios", 345 feature = "thread", 346 all(bsd, feature = "event"), 347 all(linux_kernel, feature = "net") 348 ))] 349 mod pid; 350 #[cfg(any(feature = "process", feature = "thread"))] 351 #[cfg(linux_kernel)] 352 mod prctl; 353 #[cfg(not(any(windows, target_os = "espidf", target_os = "wasi")))] 354 #[cfg(any(feature = "process", feature = "runtime", all(bsd, feature = "event")))] 355 mod signal; 356 #[cfg(not(windows))] 357 #[cfg(any( 358 feature = "fs", 359 feature = "process", 360 feature = "runtime", 361 feature = "thread", 362 feature = "time", 363 all( 364 linux_raw, 365 not(feature = "use-libc-auxv"), 366 not(feature = "use-explicitly-provided-auxv"), 367 any( 368 feature = "param", 369 feature = "process", 370 feature = "runtime", 371 feature = "time", 372 target_arch = "x86", 373 ) 374 ) 375 ))] 376 mod timespec; 377 #[cfg(not(any(windows, target_os = "wasi")))] 378 #[cfg(any( 379 feature = "fs", 380 feature = "process", 381 feature = "thread", 382 all( 383 linux_raw, 384 not(feature = "use-libc-auxv"), 385 not(feature = "use-explicitly-provided-auxv"), 386 any( 387 feature = "param", 388 feature = "runtime", 389 feature = "time", 390 target_arch = "x86", 391 ) 392 ), 393 all(linux_kernel, feature = "net") 394 ))] 395 mod ugid; 396