1//! `pipe` and related APIs.
2//!
3//! # Safety
4//!
5//! `vmsplice` is an unsafe function.
6
7#![allow(unsafe_code)]
8
9use crate::fd::OwnedFd;
10use crate::{backend, io};
11#[cfg(not(any(
12 solarish,
13 windows,
14 target_os = "espidf",
15 target_os = "haiku",
16 target_os = "redox",
17 target_os = "vita",
18 target_os = "wasi",
19)))]
20use backend::c;
21#[cfg(linux_kernel)]
22use backend::fd::AsFd;
23
24#[cfg(not(apple))]
25pub use backend::pipe::types::PipeFlags;
26
27#[cfg(linux_kernel)]
28pub use backend::pipe::types::{IoSliceRaw, SpliceFlags};
29
30/// `PIPE_BUF`—The maximum length at which writes to a pipe are atomic.
31///
32/// # References
33/// - [Linux]
34/// - [POSIX]
35///
36/// [Linux]: https://man7.org/linux/man-pages/man7/pipe.7.html
37/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html
38#[cfg(not(any(
39 solarish,
40 windows,
41 target_os = "espidf",
42 target_os = "haiku",
43 target_os = "hurd",
44 target_os = "redox",
45 target_os = "vita",
46 target_os = "wasi",
47)))]
48pub const PIPE_BUF: usize = c::PIPE_BUF;
49
50/// `pipe()`—Creates a pipe.
51///
52/// This function creates a pipe and returns two file descriptors, for the
53/// reading and writing ends of the pipe, respectively.
54///
55/// # References
56/// - [POSIX]
57/// - [Linux]
58/// - [Apple]
59/// - [FreeBSD]
60/// - [NetBSD]
61/// - [OpenBSD]
62/// - [DragonFly BSD]
63/// - [illumos]
64/// - [glibc]
65///
66/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html
67/// [Linux]: https://man7.org/linux/man-pages/man2/pipe.2.html
68/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/pipe.2.html
69/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pipe&sektion=2
70/// [NetBSD]: https://man.netbsd.org/pipe.2
71/// [OpenBSD]: https://man.openbsd.org/pipe.2
72/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pipe&section=2
73/// [illumos]: https://illumos.org/man/2/pipe
74/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/Creating-a-Pipe.html
75#[inline]
76pub fn pipe() -> io::Result<(OwnedFd, OwnedFd)> {
77 backend::pipe::syscalls::pipe()
78}
79
80/// `pipe2(flags)`—Creates a pipe, with flags.
81///
82/// This function creates a pipe and returns two file descriptors, for the
83/// reading and writing ends of the pipe, respectively.
84///
85/// # References
86/// - [Linux]
87/// - [FreeBSD]
88/// - [NetBSD]
89/// - [OpenBSD]
90/// - [DragonFly BSD]
91/// - [illumos]
92///
93/// [Linux]: https://man7.org/linux/man-pages/man2/pipe2.2.html
94/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pipe2&sektion=2
95/// [NetBSD]: https://man.netbsd.org/pipe2.2
96/// [OpenBSD]: https://man.openbsd.org/pipe2.2
97/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pipe2&section=2
98/// [illumos]: https://illumos.org/man/2/pipe2
99#[cfg(not(any(
100 apple,
101 target_os = "aix",
102 target_os = "espidf",
103 target_os = "haiku",
104 target_os = "nto"
105)))]
106#[inline]
107#[doc(alias = "pipe2")]
108pub fn pipe_with(flags: PipeFlags) -> io::Result<(OwnedFd, OwnedFd)> {
109 backend::pipe::syscalls::pipe_with(flags)
110}
111
112/// `splice(fd_in, off_in, fd_out, off_out, len, flags)`—Transfer data
113/// between a file and a pipe.
114///
115/// This function transfers up to `len` bytes of data from the file descriptor
116/// `fd_in` to the file descriptor `fd_out`, where one of the file descriptors
117/// must refer to a pipe.
118///
119/// `off_*` must be `None` if the corresponding fd refers to a pipe. Otherwise
120/// its value points to the starting offset to the file, from which the data is
121/// read/written. On success, the number of bytes read/written is added to the
122/// offset.
123///
124/// Passing `None` causes the read/write to start from the file offset, and the
125/// file offset is adjusted appropriately.
126///
127/// # References
128/// - [Linux]
129///
130/// [Linux]: https://man7.org/linux/man-pages/man2/splice.2.html
131#[cfg(linux_kernel)]
132#[inline]
133pub fn splice<FdIn: AsFd, FdOut: AsFd>(
134 fd_in: FdIn,
135 off_in: Option<&mut u64>,
136 fd_out: FdOut,
137 off_out: Option<&mut u64>,
138 len: usize,
139 flags: SpliceFlags,
140) -> io::Result<usize> {
141 backend::pipe::syscalls::splice(fd_in:fd_in.as_fd(), off_in, fd_out:fd_out.as_fd(), off_out, len, flags)
142}
143
144/// `vmsplice(fd, bufs, flags)`—Transfer data between memory and a pipe.
145///
146/// If `fd` is the write end of the pipe, the function maps the memory pointer
147/// at by `bufs` to the pipe.
148///
149/// If `fd` is the read end of the pipe, the function writes data from the pipe
150/// to said memory.
151///
152/// # Safety
153///
154/// If the memory must not be mutated (such as when `bufs` were originally
155/// immutable slices), it is up to the caller to ensure that the write end of
156/// the pipe is placed in `fd`.
157///
158/// Additionally if `SpliceFlags::GIFT` is set, the caller must also ensure
159/// that the contents of `bufs` in never modified following the call, and that
160/// all of the pointers in `bufs` are page aligned, and the lengths are
161/// multiples of a page size in bytes.
162///
163/// # References
164/// - [Linux]
165///
166/// [Linux]: https://man7.org/linux/man-pages/man2/vmsplice.2.html
167#[cfg(linux_kernel)]
168#[inline]
169pub unsafe fn vmsplice<PipeFd: AsFd>(
170 fd: PipeFd,
171 bufs: &[IoSliceRaw<'_>],
172 flags: SpliceFlags,
173) -> io::Result<usize> {
174 backend::pipe::syscalls::vmsplice(fd.as_fd(), bufs, flags)
175}
176
177/// `tee(fd_in, fd_out, len, flags)`—Copy data between pipes without
178/// consuming it.
179///
180/// This reads up to `len` bytes from `in_fd` without consuming them, and
181/// writes them to `out_fd`.
182///
183/// # References
184/// - [Linux]
185///
186/// [Linux]: https://man7.org/linux/man-pages/man2/tee.2.html
187#[cfg(linux_kernel)]
188#[inline]
189pub fn tee<FdIn: AsFd, FdOut: AsFd>(
190 fd_in: FdIn,
191 fd_out: FdOut,
192 len: usize,
193 flags: SpliceFlags,
194) -> io::Result<usize> {
195 backend::pipe::syscalls::tee(fd_in:fd_in.as_fd(), fd_out:fd_out.as_fd(), len, flags)
196}
197
198/// `fnctl(fd, F_GETPIPE_SZ)`—Return the buffer capacity of a pipe.
199///
200/// # References
201/// - [Linux]
202///
203/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html
204#[cfg(linux_kernel)]
205#[inline]
206pub fn fcntl_getpipe_size<Fd: AsFd>(fd: Fd) -> io::Result<usize> {
207 backend::pipe::syscalls::fcntl_getpipe_sz(fd.as_fd())
208}
209
210/// `fnctl(fd, F_SETPIPE_SZ)`—Set the buffer capacity of a pipe.
211///
212/// # References
213/// - [Linux]
214///
215/// [Linux]: https://man7.org/linux/man-pages/man2/fcntl.2.html
216#[cfg(linux_kernel)]
217#[inline]
218pub fn fcntl_setpipe_size<Fd: AsFd>(fd: Fd, size: usize) -> io::Result<()> {
219 backend::pipe::syscalls::fcntl_setpipe_sz(fd.as_fd(), size)
220}
221