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]> = MaybeUninit::<[OwnedFd; 2]>::uninit();
53 ret(raw:syscall!(__NR_pipe2, &mut result, flags))?;
54 let [p0: OwnedFd, p1: OwnedFd] = result.assume_init();
55 Ok((p0, p1))
56 }
57}
58
59#[inline]
60pub 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(raw: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 unsafe fn vmsplice(
83 fd: BorrowedFd<'_>,
84 bufs: &[IoSliceRaw<'_>],
85 flags: SpliceFlags,
86) -> io::Result<usize> {
87 let (bufs_addr: ArgReg<'_, A1>, bufs_len: ArgReg<'_, A2>) = slice(&bufs[..cmp::min(v1:bufs.len(), MAX_IOV)]);
88 ret_usize(raw:syscall!(__NR_vmsplice, fd, bufs_addr, bufs_len, flags))
89}
90
91#[inline]
92pub fn tee(
93 fd_in: BorrowedFd<'_>,
94 fd_out: BorrowedFd<'_>,
95 len: usize,
96 flags: SpliceFlags,
97) -> io::Result<usize> {
98 unsafe { ret_usize(raw:syscall!(__NR_tee, fd_in, fd_out, pass_usize(len), flags)) }
99}
100
101#[inline]
102pub(crate) fn fcntl_getpipe_sz(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(raw:syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETPIPE_SZ)))
110 }
111}
112
113#[inline]
114pub(crate) fn fcntl_setpipe_sz(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 ret(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 ret(raw:syscall_readonly!(
129 __NR_fcntl,
130 fd,
131 c_uint(F_SETPIPE_SZ),
132 c_int(size)
133 ))
134 }
135}
136