rustix/backend/linux_raw/pipe/
syscalls.rs

1//! linux_raw syscalls supporting `rustix::pipe`.
2//!
3//! # Safety
4//!
5//! See the `rustix::backend` module documentation for details.
6#![allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
7
8use crate::backend::conv::{c_int, c_uint, opt_mut, pass_usize, ret, ret_usize, slice};
9use crate::backend::{c, MAX_IOV};
10use crate::fd::{BorrowedFd, OwnedFd};
11use crate::io;
12use crate::pipe::{IoSliceRaw, PipeFlags, SpliceFlags};
13use core::cmp;
14use core::mem::MaybeUninit;
15use linux_raw_sys::general::{F_GETPIPE_SZ, F_SETPIPE_SZ};
16
17#[inline]
18pub(crate) fn pipe() -> io::Result<(OwnedFd, OwnedFd)> {
19    // aarch64 and risc64 omit `__NR_pipe`. On mips, `__NR_pipe` uses a special
20    // calling convention, but using it is not worth complicating our syscall
21    // wrapping infrastructure at this time.
22    #[cfg(any(
23        target_arch = "aarch64",
24        target_arch = "mips",
25        target_arch = "mips32r6",
26        target_arch = "mips64",
27        target_arch = "mips64r6",
28        target_arch = "riscv64",
29    ))]
30    {
31        pipe_with(PipeFlags::empty())
32    }
33    #[cfg(not(any(
34        target_arch = "aarch64",
35        target_arch = "mips",
36        target_arch = "mips32r6",
37        target_arch = "mips64",
38        target_arch = "mips64r6",
39        target_arch = "riscv64",
40    )))]
41    unsafe {
42        let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit();
43        ret(syscall!(__NR_pipe, &mut result))?;
44        let [p0, p1] = result.assume_init();
45        Ok((p0, p1))
46    }
47}
48
49#[inline]
50pub(crate) fn pipe_with(flags: PipeFlags) -> io::Result<(OwnedFd, OwnedFd)> {
51    unsafe {
52        let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit();
53        ret(syscall!(__NR_pipe2, &mut result, flags))?;
54        let [p0, p1] = result.assume_init();
55        Ok((p0, p1))
56    }
57}
58
59#[inline]
60pub(crate) fn splice(
61    fd_in: BorrowedFd<'_>,
62    off_in: Option<&mut u64>,
63    fd_out: BorrowedFd<'_>,
64    off_out: Option<&mut u64>,
65    len: usize,
66    flags: SpliceFlags,
67) -> io::Result<usize> {
68    unsafe {
69        ret_usize(syscall!(
70            __NR_splice,
71            fd_in,
72            opt_mut(off_in),
73            fd_out,
74            opt_mut(off_out),
75            pass_usize(len),
76            flags
77        ))
78    }
79}
80
81#[inline]
82pub(crate) unsafe fn vmsplice(
83    fd: BorrowedFd<'_>,
84    bufs: &[IoSliceRaw<'_>],
85    flags: SpliceFlags,
86) -> io::Result<usize> {
87    let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), MAX_IOV)]);
88    ret_usize(syscall!(__NR_vmsplice, fd, bufs_addr, bufs_len, flags))
89}
90
91#[inline]
92pub(crate) fn tee(
93    fd_in: BorrowedFd<'_>,
94    fd_out: BorrowedFd<'_>,
95    len: usize,
96    flags: SpliceFlags,
97) -> io::Result<usize> {
98    unsafe { ret_usize(syscall!(__NR_tee, fd_in, fd_out, pass_usize(len), flags)) }
99}
100
101#[inline]
102pub(crate) fn fcntl_getpipe_size(fd: BorrowedFd<'_>) -> io::Result<usize> {
103    #[cfg(target_pointer_width = "32")]
104    unsafe {
105        ret_usize(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETPIPE_SZ)))
106    }
107    #[cfg(target_pointer_width = "64")]
108    unsafe {
109        ret_usize(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETPIPE_SZ)))
110    }
111}
112
113#[inline]
114pub(crate) fn fcntl_setpipe_size(fd: BorrowedFd<'_>, size: usize) -> io::Result<()> {
115    let size: c::c_int = size.try_into().map_err(|_| io::Errno::PERM)?;
116
117    #[cfg(target_pointer_width = "32")]
118    unsafe {
119        let _ = ret_usize(syscall_readonly!(
120            __NR_fcntl64,
121            fd,
122            c_uint(F_SETPIPE_SZ),
123            c_int(size)
124        ))?;
125    }
126    #[cfg(target_pointer_width = "64")]
127    unsafe {
128        let _ = ret_usize(syscall_readonly!(
129            __NR_fcntl,
130            fd,
131            c_uint(F_SETPIPE_SZ),
132            c_int(size)
133        ))?;
134    }
135
136    Ok(())
137}