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