1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 // ignore-cloudabi no processes
12 // ignore-emscripten no processes
14 // Previously libstd would set stdio descriptors of a child process
15 // by `dup`ing the requested descriptors to inherit directly into the
16 // stdio descriptors. This, however, would incorrectly handle cases
17 // where the descriptors to inherit were already stdio descriptors.
18 // This test checks to avoid that regression.
20 #![cfg_attr(unix, feature(libc))]
21 #![cfg_attr(windows, allow(unused_imports))]
27 use std
::io
::{Read, Write}
;
28 use std
::io
::{stdout, stderr}
;
29 use std
::process
::{Command, Stdio}
;
32 use std
::os
::unix
::io
::FromRawFd
;
36 // Bug not present in Windows
41 let mut args
= std
::env
::args();
42 let name
= args
.next().unwrap();
43 let args
: Vec
<String
> = args
.collect();
44 if let Some("--child") = args
.get(0).map(|s
| &**s
) {
46 } else if !args
.is_empty() {
47 panic
!("unknown options");
50 let stdout_backup
= unsafe { libc::dup(libc::STDOUT_FILENO) }
;
51 let stderr_backup
= unsafe { libc::dup(libc::STDERR_FILENO) }
;
52 assert
!(stdout_backup
> -1);
53 assert
!(stderr_backup
> -1);
55 let (stdout_reader
, stdout_writer
) = pipe();
56 let (stderr_reader
, stderr_writer
) = pipe();
57 assert
!(unsafe { libc::dup2(stdout_writer, libc::STDOUT_FILENO) }
> -1);
58 assert
!(unsafe { libc::dup2(stderr_writer, libc::STDERR_FILENO) }
> -1);
60 // Make sure we close any duplicates of the writer end of the pipe,
61 // otherwise we can get stuck reading from the pipe which has open
62 // writers but no one supplying any input
63 assert_eq
!(unsafe { libc::close(stdout_writer) }
, 0);
64 assert_eq
!(unsafe { libc::close(stderr_writer) }
, 0);
66 stdout().write_all("parent stdout\n".as_bytes()).expect("failed to write to stdout");
67 stderr().write_all("parent stderr\n".as_bytes()).expect("failed to write to stderr");
72 .stdin(Stdio
::inherit())
73 .stdout(unsafe { Stdio::from_raw_fd(libc::STDERR_FILENO) }
)
74 .stderr(unsafe { Stdio::from_raw_fd(libc::STDOUT_FILENO) }
)
78 // The Stdio passed into the Command took over (and closed) std{out, err}
79 // so we should restore them as they were.
80 assert
!(unsafe { libc::dup2(stdout_backup, libc::STDOUT_FILENO) }
> -1);
81 assert
!(unsafe { libc::dup2(stderr_backup, libc::STDERR_FILENO) }
> -1);
83 // Using File as a shim around the descriptor
84 let mut read
= String
::new();
85 let mut f
: File
= unsafe { FromRawFd::from_raw_fd(stdout_reader) }
;
86 f
.read_to_string(&mut read
).expect("failed to read from stdout file");
87 assert_eq
!(read
, "parent stdout\nchild stderr\n");
89 // Using File as a shim around the descriptor
91 let mut f
: File
= unsafe { FromRawFd::from_raw_fd(stderr_reader) }
;
92 f
.read_to_string(&mut read
).expect("failed to read from stderr file");
93 assert_eq
!(read
, "parent stderr\nchild stdout\n");
95 assert
!(child
.expect("failed to execute child process").wait().unwrap().success());
100 stdout().write_all("child stdout\n".as_bytes()).expect("child failed to write to stdout");
101 stderr().write_all("child stderr\n".as_bytes()).expect("child failed to write to stderr");
105 /// Returns a pipe (reader, writer combo)
106 fn pipe() -> (i32, i32) {
107 let mut fds
= [0; 2];
108 assert_eq
!(unsafe { libc::pipe(fds.as_mut_ptr()) }
, 0);