summaryrefslogtreecommitdiffstats
path: root/vendor/rustix/examples/dup2_to_replace_stdio.rs
blob: cc856591555fc472e61c64fdf2fd16c2fdf137e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//! This is an example of how to use `dup2` to replace the stdin and stdout
//! file descriptors.

#[cfg(not(windows))]
fn main() {
    use rustix::io::{dup2, pipe};
    use std::io::{BufRead, BufReader};
    use std::mem::forget;

    // Create some new file descriptors that we'll use to replace stdio's file
    // descriptors with.
    let (reader, writer) = pipe().unwrap();

    // Acquire `OwnedFd` instances for stdin and stdout. These APIs are `unsafe`
    // because in general, with low-level APIs like this, libraries can't assume
    // that stdin and stdout will be open or safe to use. It's ok here, because
    // we're directly inside `main`, so we know that stdin and stdout haven't
    // been closed and aren't being used for other purposes.
    let (mut stdin, mut stdout) = unsafe { (rustix::io::take_stdin(), rustix::io::take_stdout()) };

    // Use `dup2` to copy our new file descriptors over the stdio file descriptors.
    //
    // These take their second argument as an `&mut OwnedFd` rather than the
    // usual `impl AsFd` because they conceptually do a `close` on the original
    // file descriptor, which one shouldn't be able to do with just a
    // `BorrowedFd`.
    dup2(&reader, &mut stdin).unwrap();
    dup2(&writer, &mut stdout).unwrap();

    // Then, forget the stdio `OwnedFd`s, because actually dropping them would
    // close them. Here, we want stdin and stdout to remain open for the rest
    // of the program.
    forget(stdin);
    forget(stdout);

    // We can also drop the original file descriptors now, since `dup2` creates
    // new file descriptors with independent lifetimes.
    drop(reader);
    drop(writer);

    // Now we can print to "stdout" in the usual way, and it'll go to our pipe.
    println!("hello, world!");

    // And we can read from stdin, and it'll read from our pipe. It's a little
    // silly that we connected our stdout to our own stdin, but it's just an
    // example :-).
    let mut s = String::new();
    BufReader::new(std::io::stdin()).read_line(&mut s).unwrap();
    assert_eq!(s, "hello, world!\n");
}

#[cfg(windows)]
fn main() {
    unimplemented!()
}