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 56 57 58 59 60 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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
// run-pass
// ignore-android
// ignore-emscripten no processes
// ignore-sgx no processes
// revisions: mir thir
// [thir]compile-flags: -Zthir-unsafeck
#![feature(rustc_private)]
extern crate libc;
use std::process::{Command, Stdio};
use std::env;
use std::io::{self, Read, Write};
#[cfg(unix)]
unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
let doit = |a| {
let r = libc::dup(a);
assert!(r >= 0);
return r
};
let a = doit(0);
let b = doit(1);
let c = doit(2);
assert!(libc::close(0) >= 0);
assert!(libc::close(1) >= 0);
assert!(libc::close(2) >= 0);
let r = f();
assert!(libc::dup2(a, 0) >= 0);
assert!(libc::dup2(b, 1) >= 0);
assert!(libc::dup2(c, 2) >= 0);
return r
}
#[cfg(unix)]
fn assert_fd_is_valid(fd: libc::c_int) {
if unsafe { libc::fcntl(fd, libc::F_GETFD) == -1 } {
panic!("file descriptor {} is not valid: {}", fd, io::Error::last_os_error());
}
}
#[cfg(windows)]
fn assert_fd_is_valid(_fd: libc::c_int) {}
#[cfg(windows)]
unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
type DWORD = u32;
type HANDLE = *mut u8;
type BOOL = i32;
const STD_INPUT_HANDLE: DWORD = -10i32 as DWORD;
const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
extern "system" {
fn GetStdHandle(which: DWORD) -> HANDLE;
fn SetStdHandle(which: DWORD, handle: HANDLE) -> BOOL;
}
let doit = |id| {
let handle = GetStdHandle(id);
assert!(handle != INVALID_HANDLE_VALUE);
assert!(SetStdHandle(id, INVALID_HANDLE_VALUE) != 0);
return handle
};
let a = doit(STD_INPUT_HANDLE);
let b = doit(STD_OUTPUT_HANDLE);
let c = doit(STD_ERROR_HANDLE);
let r = f();
let doit = |id, handle| {
assert!(SetStdHandle(id, handle) != 0);
};
doit(STD_INPUT_HANDLE, a);
doit(STD_OUTPUT_HANDLE, b);
doit(STD_ERROR_HANDLE, c);
return r
}
fn main() {
if env::args().len() > 1 {
// Writing to stdout & stderr should not panic.
println!("test");
assert!(io::stdout().write(b"test\n").is_ok());
assert!(io::stderr().write(b"test\n").is_ok());
// Stdin should be at EOF.
assert_eq!(io::stdin().read(&mut [0; 10]).unwrap(), 0);
// Standard file descriptors should be valid on UNIX:
assert_fd_is_valid(0);
assert_fd_is_valid(1);
assert_fd_is_valid(2);
return
}
// First, make sure reads/writes without stdio work if stdio itself is
// missing.
let (a, b, c) = unsafe {
without_stdio(|| {
let a = io::stdout().write(b"test\n");
let b = io::stderr().write(b"test\n");
let c = io::stdin().read(&mut [0; 10]);
(a, b, c)
})
};
assert_eq!(a.unwrap(), 5);
assert_eq!(b.unwrap(), 5);
assert_eq!(c.unwrap(), 0);
// Second, spawn a child and do some work with "null" descriptors to make
// sure it's ok
let me = env::current_exe().unwrap();
let status = Command::new(&me)
.arg("next")
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.status().unwrap();
assert!(status.success(), "{} isn't a success", status);
// Finally, close everything then spawn a child to make sure everything is
// *still* ok.
let status = unsafe {
without_stdio(|| Command::new(&me).arg("next").status())
}.unwrap();
assert!(status.success(), "{} isn't a success", status);
}
|