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
8 use crate::backend::conv::{c_int, c_uint, opt_mut, pass_usize, ret, ret_usize, slice};
9 use crate::backend::{c, MAX_IOV};
10 use crate::fd::{BorrowedFd, OwnedFd};
11 use crate::io;
12 use crate::pipe::{IoSliceRaw, PipeFlags, SpliceFlags};
13 use core::cmp;
14 use core::mem::MaybeUninit;
15 use linux_raw_sys::general::{F_GETPIPE_SZ, F_SETPIPE_SZ};
16
17 #[inline]
pipe() -> io::Result<(OwnedFd, OwnedFd)>18 pub(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]
pipe_with(flags: PipeFlags) -> io::Result<(OwnedFd, OwnedFd)>50 pub(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]
splice( fd_in: BorrowedFd<'_>, off_in: Option<&mut u64>, fd_out: BorrowedFd<'_>, off_out: Option<&mut u64>, len: usize, flags: SpliceFlags, ) -> io::Result<usize>60 pub 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]
vmsplice( fd: BorrowedFd<'_>, bufs: &[IoSliceRaw<'_>], flags: SpliceFlags, ) -> io::Result<usize>82 pub 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]
tee( fd_in: BorrowedFd<'_>, fd_out: BorrowedFd<'_>, len: usize, flags: SpliceFlags, ) -> io::Result<usize>92 pub 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]
fcntl_getpipe_sz(fd: BorrowedFd<'_>) -> io::Result<usize>102 pub(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(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETPIPE_SZ)))
110 }
111 }
112
113 #[inline]
fcntl_setpipe_sz(fd: BorrowedFd<'_>, size: usize) -> io::Result<()>114 pub(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(syscall_readonly!(
129 __NR_fcntl,
130 fd,
131 c_uint(F_SETPIPE_SZ),
132 c_int(size)
133 ))
134 }
135 }
136