rustix/io/ioctl.rs
1//! The Unix `ioctl` function is effectively lots of different functions hidden
2//! behind a single dynamic dispatch interface. In order to provide a type-safe
3//! API, rustix makes them all separate functions so that they can have
4//! dedicated static type signatures.
5//!
6//! Some ioctls, such as those related to filesystems, terminals, and
7//! processes, live in other top-level API modules.
8
9#![allow(unsafe_code)]
10
11use crate::{backend, io, ioctl};
12use backend::c;
13use backend::fd::AsFd;
14
15/// `ioctl(fd, FIOCLEX, NULL)`—Set the close-on-exec flag.
16///
17/// This is similar to `fcntl(fd, F_SETFD, FD_CLOEXEC)`, except that it avoids
18/// clearing any other flags that might be set.
19///
20/// Linux: Note that `ioctl` can not be used on `OFlags::PATH` file
21/// descriptors.
22#[cfg(any(apple, linux_kernel))]
23#[inline]
24#[doc(alias = "FIOCLEX")]
25#[doc(alias = "FD_CLOEXEC")]
26pub fn ioctl_fioclex<Fd: AsFd>(fd: Fd) -> io::Result<()> {
27 // SAFETY: `FIOCLEX` is a no-argument setter opcode.
28 unsafe {
29 let ctl = ioctl::NoArg::<{ c::FIOCLEX }>::new();
30 ioctl::ioctl(fd, ctl)
31 }
32}
33
34/// `ioctl(fd, FIONCLEX, NULL)`—Remove the close-on-exec flag.
35///
36/// This is similar to `fcntl_setfd(fd, FdFlags::empty())`, except that it avoids
37/// clearing any other flags that might be set.
38///
39/// Linux: Note that `ioctl` can not be used on `OFlags::PATH` file
40/// descriptors.
41#[cfg(any(apple, linux_kernel))]
42#[inline]
43#[doc(alias = "FIONCLEX")]
44pub fn ioctl_fionclex<Fd: AsFd>(fd: Fd) -> io::Result<()> {
45 // SAFETY: `FIONCLEX` is a no-argument setter opcode.
46 unsafe {
47 let ctl = ioctl::NoArg::<{ c::FIONCLEX }>::new();
48 ioctl::ioctl(fd, ctl)
49 }
50}
51
52/// `ioctl(fd, FIONBIO, &value)`—Enables or disables non-blocking mode.
53///
54/// # References
55/// - [Winsock]
56/// - [NetBSD]
57/// - [OpenBSD]
58///
59/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/winsock/winsock-ioctls#unix-ioctl-codes
60/// [NetBSD]: https://man.netbsd.org/ioctl.2#GENERIC%20IOCTLS
61/// [OpenBSD]: https://man.openbsd.org/ioctl.2#GENERIC_IOCTLS
62#[inline]
63#[doc(alias = "FIONBIO")]
64pub fn ioctl_fionbio<Fd: AsFd>(fd: Fd, value: bool) -> io::Result<()> {
65 // SAFETY: `FIONBIO` is a pointer setter opcode.
66 unsafe {
67 let ctl = ioctl::Setter::<{ c::FIONBIO }, c::c_int>::new(value.into());
68 ioctl::ioctl(fd, ctl)
69 }
70}
71
72/// `ioctl(fd, FIONREAD)`—Returns the number of bytes ready to be read.
73///
74/// The result of this function gets silently coerced into a C `int` by the OS,
75/// so it may contain a wrapped value.
76///
77/// # References
78/// - [Linux]
79/// - [Winsock]
80/// - [FreeBSD]
81/// - [NetBSD]
82/// - [OpenBSD]
83///
84/// [Linux]: https://man7.org/linux/man-pages/man2/ioctl_tty.2.html
85/// [Winsock]: https://docs.microsoft.com/en-us/windows/win32/winsock/winsock-ioctls#unix-ioctl-codes
86/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=ioctl&sektion=2#GENERIC%09IOCTLS
87/// [NetBSD]: https://man.netbsd.org/ioctl.2#GENERIC%20IOCTLS
88/// [OpenBSD]: https://man.openbsd.org/ioctl.2#GENERIC_IOCTLS
89#[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))]
90#[inline]
91#[doc(alias = "FIONREAD")]
92pub fn ioctl_fionread<Fd: AsFd>(fd: Fd) -> io::Result<u64> {
93 // SAFETY: `FIONREAD` is a getter opcode that gets a `c_int`.
94 unsafe {
95 let ctl = ioctl::Getter::<{ c::FIONREAD }, c::c_int>::new();
96 ioctl::ioctl(fd, ctl).map(|n| n as u64)
97 }
98}