]>
Commit | Line | Data |
---|---|---|
416331ca | 1 | // run-pass |
476ff2be | 2 | // ignore-android |
2c00a5a8 XL |
3 | // ignore-cloudabi no processes |
4 | // ignore-emscripten no processes | |
48663c56 | 5 | // ignore-sgx no processes |
5bcae85e | 6 | |
0731742a | 7 | #![feature(rustc_private)] |
7453a54e SL |
8 | |
9 | extern crate libc; | |
10 | ||
11 | use std::process::{Command, Stdio}; | |
12 | use std::env; | |
13 | use std::io::{self, Read, Write}; | |
14 | ||
15 | #[cfg(unix)] | |
16 | unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R { | |
17 | let doit = |a| { | |
18 | let r = libc::dup(a); | |
19 | assert!(r >= 0); | |
20 | return r | |
21 | }; | |
22 | let a = doit(0); | |
23 | let b = doit(1); | |
24 | let c = doit(2); | |
25 | ||
26 | assert!(libc::close(0) >= 0); | |
27 | assert!(libc::close(1) >= 0); | |
28 | assert!(libc::close(2) >= 0); | |
29 | ||
30 | let r = f(); | |
31 | ||
32 | assert!(libc::dup2(a, 0) >= 0); | |
33 | assert!(libc::dup2(b, 1) >= 0); | |
34 | assert!(libc::dup2(c, 2) >= 0); | |
35 | ||
36 | return r | |
37 | } | |
38 | ||
1b1a35ee XL |
39 | #[cfg(unix)] |
40 | fn assert_fd_is_valid(fd: libc::c_int) { | |
41 | if unsafe { libc::fcntl(fd, libc::F_GETFD) == -1 } { | |
42 | panic!("file descriptor {} is not valid: {}", fd, io::Error::last_os_error()); | |
43 | } | |
44 | } | |
45 | ||
46 | #[cfg(windows)] | |
47 | fn assert_fd_is_valid(_fd: libc::c_int) {} | |
48 | ||
7453a54e SL |
49 | #[cfg(windows)] |
50 | unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R { | |
51 | type DWORD = u32; | |
52 | type HANDLE = *mut u8; | |
53 | type BOOL = i32; | |
54 | ||
55 | const STD_INPUT_HANDLE: DWORD = -10i32 as DWORD; | |
56 | const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD; | |
57 | const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD; | |
58 | const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE; | |
59 | ||
60 | extern "system" { | |
61 | fn GetStdHandle(which: DWORD) -> HANDLE; | |
62 | fn SetStdHandle(which: DWORD, handle: HANDLE) -> BOOL; | |
63 | } | |
64 | ||
65 | let doit = |id| { | |
66 | let handle = GetStdHandle(id); | |
67 | assert!(handle != INVALID_HANDLE_VALUE); | |
68 | assert!(SetStdHandle(id, INVALID_HANDLE_VALUE) != 0); | |
69 | return handle | |
70 | }; | |
71 | ||
72 | let a = doit(STD_INPUT_HANDLE); | |
73 | let b = doit(STD_OUTPUT_HANDLE); | |
74 | let c = doit(STD_ERROR_HANDLE); | |
75 | ||
76 | let r = f(); | |
77 | ||
78 | let doit = |id, handle| { | |
79 | assert!(SetStdHandle(id, handle) != 0); | |
80 | }; | |
81 | doit(STD_INPUT_HANDLE, a); | |
82 | doit(STD_OUTPUT_HANDLE, b); | |
83 | doit(STD_ERROR_HANDLE, c); | |
84 | ||
85 | return r | |
86 | } | |
87 | ||
88 | fn main() { | |
89 | if env::args().len() > 1 { | |
1b1a35ee | 90 | // Writing to stdout & stderr should not panic. |
7453a54e SL |
91 | println!("test"); |
92 | assert!(io::stdout().write(b"test\n").is_ok()); | |
93 | assert!(io::stderr().write(b"test\n").is_ok()); | |
1b1a35ee XL |
94 | |
95 | // Stdin should be at EOF. | |
7453a54e | 96 | assert_eq!(io::stdin().read(&mut [0; 10]).unwrap(), 0); |
1b1a35ee XL |
97 | |
98 | // Standard file descriptors should be valid on UNIX: | |
99 | assert_fd_is_valid(0); | |
100 | assert_fd_is_valid(1); | |
101 | assert_fd_is_valid(2); | |
7453a54e SL |
102 | return |
103 | } | |
104 | ||
105 | // First, make sure reads/writes without stdio work if stdio itself is | |
106 | // missing. | |
107 | let (a, b, c) = unsafe { | |
108 | without_stdio(|| { | |
109 | let a = io::stdout().write(b"test\n"); | |
110 | let b = io::stderr().write(b"test\n"); | |
111 | let c = io::stdin().read(&mut [0; 10]); | |
112 | ||
113 | (a, b, c) | |
114 | }) | |
115 | }; | |
116 | ||
117 | assert_eq!(a.unwrap(), 5); | |
118 | assert_eq!(b.unwrap(), 5); | |
119 | assert_eq!(c.unwrap(), 0); | |
120 | ||
121 | // Second, spawn a child and do some work with "null" descriptors to make | |
122 | // sure it's ok | |
123 | let me = env::current_exe().unwrap(); | |
124 | let status = Command::new(&me) | |
125 | .arg("next") | |
126 | .stdin(Stdio::null()) | |
127 | .stdout(Stdio::null()) | |
128 | .stderr(Stdio::null()) | |
129 | .status().unwrap(); | |
1b1a35ee | 130 | assert!(status.success(), "{} isn't a success", status); |
7453a54e SL |
131 | |
132 | // Finally, close everything then spawn a child to make sure everything is | |
133 | // *still* ok. | |
134 | let status = unsafe { | |
135 | without_stdio(|| Command::new(&me).arg("next").status()) | |
136 | }.unwrap(); | |
1b1a35ee | 137 | assert!(status.success(), "{} isn't a success", status); |
7453a54e | 138 | } |