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