Function nc::tee

source ·
pub unsafe fn tee(
    fd_in: i32,
    fd_out: i32,
    len: size_t,
    flags: u32
) -> Result<ssize_t, Errno>
Expand description

Duplicate pipe content.

§Example

let mut fds_left = [0, 0];
let ret = unsafe { nc::pipe2(&mut fds_left, 0) };
assert!(ret.is_ok());

let mut fds_right = [0, 0];
let ret = unsafe { nc::pipe2(&mut fds_right, 0) };
assert!(ret.is_ok());

let msg = "Hello, Rust";
let ret = unsafe { nc::write(fds_left[1], msg.as_ptr() as usize, msg.len()) };
assert!(ret.is_ok());
let n_write = ret.unwrap() as nc::size_t;
assert_eq!(n_write, msg.len());

let ret = unsafe { nc::tee(fds_left[0], fds_right[1], n_write, nc::SPLICE_F_NONBLOCK) };
assert!(ret.is_ok());

let mut buf = [0u8; 64];
let buf_len = buf.len();
let ret = unsafe { nc::read(fds_right[0], buf.as_mut_ptr() as usize, buf_len) };
assert!(ret.is_ok());
let n_read = ret.unwrap() as nc::size_t;
assert_eq!(n_read, n_write);
let read_msg = std::str::from_utf8(&buf[..n_read]);
assert!(read_msg.is_ok());
assert_eq!(Ok(msg), read_msg);

unsafe {
    assert!(nc::close(fds_left[0]).is_ok());
    assert!(nc::close(fds_left[1]).is_ok());
    assert!(nc::close(fds_right[0]).is_ok());
    assert!(nc::close(fds_right[1]).is_ok());
}
Examples found in repository?
examples/tee.rs (lines 79-84)
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
fn main() {
    let output_file = "/tmp/nc-splice";
    let ret = unsafe {
        nc::openat(
            nc::AT_FDCWD,
            output_file,
            nc::O_WRONLY | nc::O_CREAT | nc::O_TRUNC,
            0o644,
        )
    };
    assert!(ret.is_ok());
    let fd = ret.unwrap();

    // Tee stdin to stdout
    loop {
        let stdin_fileno = 0;
        let stdout_fileno = 1;
        let ret = unsafe {
            nc::tee(
                stdin_fileno,
                stdout_fileno,
                usize::MAX,
                nc::SPLICE_F_NONBLOCK,
            )
        };
        let mut tee_len = match ret {
            Ok(0) => break,
            Err(nc::EAGAIN) => continue,
            Err(errno) => {
                eprintln!("tee error: {}", nc::strerror(errno));
                unsafe { nc::exit(1) };
            }
            Ok(len) => len,
        };

        // Consume stdin by splicing it to a file.
        while tee_len > 0 {
            let ret = unsafe {
                nc::splice(
                    stdin_fileno,
                    None,
                    fd,
                    None,
                    tee_len as usize,
                    nc::SPLICE_F_MOVE,
                )
            };
            match ret {
                Err(errno) => {
                    eprintln!("splice error: {}", nc::strerror(errno));
                    break;
                }
                Ok(len) => tee_len -= len,
            }
        }
    }

    let ret = unsafe { nc::close(fd) };
    assert!(ret.is_ok());
}