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