pub type LPWSTR = *mut WCHAR;
pub type LPSTR = *mut CHAR;
+ pub type LPTSTR = *mut CHAR;
// Not really, but opaque to us.
pub type LPSECURITY_ATTRIBUTES = LPVOID;
pub type LPVOID = *mut c_void;
+ pub type LPBYTE = *mut BYTE;
pub type LPWORD = *mut WORD;
+ pub type LPDWORD = *mut DWORD;
+ pub type LPHANDLE = *mut HANDLE;
pub type LRESULT = LONG_PTR;
pub type PBOOL = *mut BOOL;
pub type time64_t = i64;
pub type int64 = i64;
+
+ pub struct STARTUPINFO {
+ cb: DWORD,
+ lpReserved: LPTSTR,
+ lpDesktop: LPTSTR,
+ lpTitle: LPTSTR,
+ dwX: DWORD,
+ dwY: DWORD,
+ dwXSize: DWORD,
+ dwYSize: DWORD,
+ dwXCountChars: DWORD,
+ dwYCountCharts: DWORD,
+ dwFillAttribute: DWORD,
+ dwFlags: DWORD,
+ wShowWindow: WORD,
+ cbReserved2: WORD,
+ lpReserved2: LPBYTE,
+ hStdInput: HANDLE,
+ hStdOutput: HANDLE,
+ hStdError: HANDLE
+ }
+ pub type LPSTARTUPINFO = *mut STARTUPINFO;
+
+ pub struct PROCESS_INFORMATION {
+ hProcess: HANDLE,
+ hThread: HANDLE,
+ dwProcessId: DWORD,
+ dwThreadId: DWORD
+ }
+ pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION;
}
}
}
pub mod bsd44 {
}
pub mod extra {
+ use libc::types::os::arch::extra::{DWORD, BOOL};
+
+ pub static TRUE : BOOL = 1;
+ pub static FALSE : BOOL = 0;
+
pub static O_TEXT : int = 16384;
pub static O_BINARY : int = 32768;
pub static O_NOINHERIT: int = 128;
pub static ERROR_SUCCESS : int = 0;
pub static ERROR_INSUFFICIENT_BUFFER : int = 122;
pub static INVALID_HANDLE_VALUE: int = -1;
+
+ pub static DELETE : DWORD = 0x00010000;
+ pub static READ_CONTROL : DWORD = 0x00020000;
+ pub static SYNCHRONIZE : DWORD = 0x00100000;
+ pub static WRITE_DAC : DWORD = 0x00040000;
+ pub static WRITE_OWNER : DWORD = 0x00080000;
+
+ pub static PROCESS_CREATE_PROCESS : DWORD = 0x0080;
+ pub static PROCESS_CREATE_THREAD : DWORD = 0x0002;
+ pub static PROCESS_DUP_HANDLE : DWORD = 0x0040;
+ pub static PROCESS_QUERY_INFORMATION : DWORD = 0x0400;
+ pub static PROCESS_QUERY_LIMITED_INFORMATION : DWORD = 0x1000;
+ pub static PROCESS_SET_INFORMATION : DWORD = 0x0200;
+ pub static PROCESS_SET_QUOTA : DWORD = 0x0100;
+ pub static PROCESS_SUSPEND_RESUME : DWORD = 0x0800;
+ pub static PROCESS_TERMINATE : DWORD = 0x0001;
+ pub static PROCESS_VM_OPERATION : DWORD = 0x0008;
+ pub static PROCESS_VM_READ : DWORD = 0x0010;
+ pub static PROCESS_VM_WRITE : DWORD = 0x0020;
+
+ pub static STARTF_FORCEONFEEDBACK : DWORD = 0x00000040;
+ pub static STARTF_FORCEOFFFEEDBACK : DWORD = 0x00000080;
+ pub static STARTF_PREVENTPINNING : DWORD = 0x00002000;
+ pub static STARTF_RUNFULLSCREEN : DWORD = 0x00000020;
+ pub static STARTF_TITLEISAPPID : DWORD = 0x00001000;
+ pub static STARTF_TITLEISLINKNAME : DWORD = 0x00000800;
+ pub static STARTF_USECOUNTCHARS : DWORD = 0x00000008;
+ pub static STARTF_USEFILLATTRIBUTE : DWORD = 0x00000010;
+ pub static STARTF_USEHOTKEY : DWORD = 0x00000200;
+ pub static STARTF_USEPOSITION : DWORD = 0x00000004;
+ pub static STARTF_USESHOWWINDOW : DWORD = 0x00000001;
+ pub static STARTF_USESIZE : DWORD = 0x00000002;
+ pub static STARTF_USESTDHANDLES : DWORD = 0x00000100;
+
+ pub static WAIT_ABANDONED : DWORD = 0x00000080;
+ pub static WAIT_OBJECT_0 : DWORD = 0x00000000;
+ pub static WAIT_TIMEOUT : DWORD = 0x00000102;
+ pub static WAIT_FAILED : DWORD = -1;
+
+ pub static DUPLICATE_CLOSE_SOURCE : DWORD = 0x00000001;
+ pub static DUPLICATE_SAME_ACCESS : DWORD = 0x00000002;
+
+ pub static INFINITE : DWORD = -1;
+ pub static STILL_ACTIVE : DWORD = 259;
}
}
unsafe fn sysctlnametomib(name: *c_char, mibp: *mut c_int,
sizep: *mut size_t) -> c_int;
+
+ unsafe fn getdtablesize() -> c_int;
}
}
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
+ pub mod bsd44 {
+ use libc::types::os::arch::c95::{c_int};
+
+ #[abi = "cdecl"]
+ pub extern {
+ unsafe fn getdtablesize() -> c_int;
+ }
+ }
+
+
#[cfg(target_os = "win32")]
pub mod bsd44 {
}
pub mod kernel32 {
use libc::types::os::arch::c95::{c_uint};
use libc::types::os::arch::extra::{BOOL, DWORD, HMODULE};
- use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPTCH};
- use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES};
- use libc::types::os::arch::extra::{HANDLE};
+ use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPCTSTR,
+ LPTSTR, LPTCH, LPDWORD, LPVOID};
+ use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, LPSTARTUPINFO,
+ LPPROCESS_INFORMATION};
+ use libc::types::os::arch::extra::{HANDLE, LPHANDLE};
#[abi = "stdcall"]
pub extern "stdcall" {
findFileData: HANDLE)
-> BOOL;
unsafe fn FindClose(findFile: HANDLE) -> BOOL;
+ unsafe fn DuplicateHandle(hSourceProcessHandle: HANDLE,
+ hSourceHandle: HANDLE,
+ hTargetProcessHandle: HANDLE,
+ lpTargetHandle: LPHANDLE,
+ dwDesiredAccess: DWORD,
+ bInheritHandle: BOOL,
+ dwOptions: DWORD) -> BOOL;
unsafe fn CloseHandle(hObject: HANDLE) -> BOOL;
+ unsafe fn OpenProcess(dwDesiredAccess: DWORD,
+ bInheritHandle: BOOL,
+ dwProcessId: DWORD) -> HANDLE;
+ unsafe fn GetCurrentProcess() -> HANDLE;
+ unsafe fn CreateProcessA(lpApplicationName: LPCTSTR,
+ lpCommandLine: LPTSTR,
+ lpProcessAttributes: LPSECURITY_ATTRIBUTES,
+ lpThreadAttributes: LPSECURITY_ATTRIBUTES,
+ bInheritHandles: BOOL,
+ dwCreationFlags: DWORD,
+ lpEnvironment: LPVOID,
+ lpCurrentDirectory: LPCTSTR,
+ lpStartupInfo: LPSTARTUPINFO,
+ lpProcessInformation: LPPROCESS_INFORMATION) -> BOOL;
+ unsafe fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
unsafe fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint) -> BOOL;
+ unsafe fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL;
}
}
pub mod msvcrt {
- use libc::types::os::arch::c95::c_int;
+ use libc::types::os::arch::c95::{c_int, c_long};
#[abi = "cdecl"]
#[nolink]
pub extern {
#[link_name = "_commit"]
unsafe fn commit(fd: c_int) -> c_int;
+
+ #[link_name = "_get_osfhandle"]
+ unsafe fn get_osfhandle(fd: c_int) -> c_long;
}
}
}
// inheritance has to be handled in a different way that I do not
// fully understand. Here we explicitly make the pipe non-inheritable,
// which means to pass it to a subprocess they need to be duplicated
- // first, as in rust_run_program.
+ // first, as in core::run.
let mut fds = Pipe {in: 0 as c_int,
out: 0 as c_int };
let res = libc::pipe(&mut fds.in, 1024 as ::libc::c_uint,
use task;
use vec;
-pub mod rustrt {
- use libc::{c_int, c_void};
- use libc;
- use run;
-
- #[abi = "cdecl"]
- pub extern {
- unsafe fn rust_run_program(argv: **libc::c_char,
- envp: *c_void,
- dir: *libc::c_char,
- in_fd: c_int,
- out_fd: c_int,
- err_fd: c_int) -> run::RunProgramResult;
- unsafe fn rust_process_wait(pid: c_int) -> c_int;
- }
-}
-
-pub struct RunProgramResult {
- // the process id of the program, or -1 if in case of errors
- pid: pid_t,
- // a handle to the process - on unix this will always be NULL, but on windows it will be a
- // HANDLE to the process, which will prevent the pid being re-used until the handle is closed.
- handle: *(),
-}
-
/// A value representing a child process
pub struct Program {
priv pid: pid_t,
return res.pid;
}
+struct RunProgramResult {
+ // the process id of the program (this should never be negative)
+ pid: pid_t,
+ // a handle to the process - on unix this will always be NULL, but on windows it will be a
+ // HANDLE to the process, which will prevent the pid being re-used until the handle is closed.
+ handle: *(),
+}
+
+#[cfg(windows)]
fn spawn_process_internal(prog: &str, args: &[~str],
env: &Option<~[(~str,~str)]>,
dir: &Option<~str>,
in_fd: c_int, out_fd: c_int, err_fd: c_int) -> RunProgramResult {
+
+ use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
+ use libc::consts::os::extra::{
+ TRUE, FALSE,
+ STARTF_USESTDHANDLES,
+ INVALID_HANDLE_VALUE,
+ DUPLICATE_SAME_ACCESS
+ };
+ use libc::funcs::extra::kernel32::{
+ GetCurrentProcess,
+ DuplicateHandle,
+ CloseHandle,
+ CreateProcessA
+ };
+ use libc::funcs::extra::msvcrt::get_osfhandle;
+
unsafe {
- do with_argv(prog, args) |argv| {
- do with_envp(env) |envp| {
- do with_dirp(dir) |dirp| {
- rustrt::rust_run_program(argv, envp, dirp, in_fd, out_fd, err_fd)
+
+ let mut si = zeroed_startupinfo();
+ si.cb = sys::size_of::<STARTUPINFO>() as DWORD;
+ si.dwFlags = STARTF_USESTDHANDLES;
+
+ let cur_proc = GetCurrentProcess();
+
+ let orig_std_in = get_osfhandle(if in_fd > 0 { in_fd } else { 0 }) as HANDLE;
+ if orig_std_in == INVALID_HANDLE_VALUE as HANDLE {
+ fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error()));
+ }
+ if DuplicateHandle(cur_proc, orig_std_in, cur_proc, &mut si.hStdInput,
+ 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
+ fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error()));
+ }
+
+ let orig_std_out = get_osfhandle(if out_fd > 0 { out_fd } else { 1 }) as HANDLE;
+ if orig_std_out == INVALID_HANDLE_VALUE as HANDLE {
+ fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error()));
+ }
+ if DuplicateHandle(cur_proc, orig_std_out, cur_proc, &mut si.hStdOutput,
+ 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
+ fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error()));
+ }
+
+ let orig_std_err = get_osfhandle(if err_fd > 0 { err_fd } else { 2 }) as HANDLE;
+ if orig_std_err as HANDLE == INVALID_HANDLE_VALUE as HANDLE {
+ fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error()));
+ }
+ if DuplicateHandle(cur_proc, orig_std_err, cur_proc, &mut si.hStdError,
+ 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
+ fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error()));
+ }
+
+ let cmd = make_command_line(prog, args);
+ let mut pi = zeroed_process_information();
+ let mut create_err = None;
+
+ do with_envp(env) |envp| {
+ do with_dirp(dir) |dirp| {
+ do str::as_c_str(cmd) |cmdp| {
+ let created = CreateProcessA(ptr::null(), cast::transmute(cmdp),
+ ptr::mut_null(), ptr::mut_null(), TRUE,
+ 0, envp, dirp, &mut si, &mut pi);
+ if created == FALSE {
+ create_err = Some(os::last_os_error());
+ }
}
}
}
+
+ CloseHandle(si.hStdInput);
+ CloseHandle(si.hStdOutput);
+ CloseHandle(si.hStdError);
+
+ for create_err.each |msg| {
+ fail!(fmt!("failure in CreateProcess: %s", *msg));
+ }
+
+ // We close the thread handle because we don't care about keeping the thread id valid,
+ // and we aren't keeping the thread handle around to be able to close it later. We don't
+ // close the process handle however because we want the process id to stay valid at least
+ // until the calling code closes the process handle.
+ CloseHandle(pi.hThread);
+
+ RunProgramResult {
+ pid: pi.dwProcessId as pid_t,
+ handle: pi.hProcess as *()
+ }
+ }
+}
+
+#[cfg(windows)]
+fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO {
+ libc::types::os::arch::extra::STARTUPINFO {
+ cb: 0,
+ lpReserved: ptr::mut_null(),
+ lpDesktop: ptr::mut_null(),
+ lpTitle: ptr::mut_null(),
+ dwX: 0,
+ dwY: 0,
+ dwXSize: 0,
+ dwYSize: 0,
+ dwXCountChars: 0,
+ dwYCountCharts: 0,
+ dwFillAttribute: 0,
+ dwFlags: 0,
+ wShowWindow: 0,
+ cbReserved2: 0,
+ lpReserved2: ptr::mut_null(),
+ hStdInput: ptr::mut_null(),
+ hStdOutput: ptr::mut_null(),
+ hStdError: ptr::mut_null()
+ }
+}
+
+#[cfg(windows)]
+fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION {
+ libc::types::os::arch::extra::PROCESS_INFORMATION {
+ hProcess: ptr::mut_null(),
+ hThread: ptr::mut_null(),
+ dwProcessId: 0,
+ dwThreadId: 0
}
}
+// FIXME: this is only pub so it can be tested (see issue #4536)
+#[cfg(windows)]
+pub fn make_command_line(prog: &str, args: &[~str]) -> ~str {
+
+ let mut cmd = ~"";
+ append_arg(&mut cmd, prog);
+ for args.each |arg| {
+ cmd.push_char(' ');
+ append_arg(&mut cmd, *arg);
+ }
+ return cmd;
+
+ fn append_arg(cmd: &mut ~str, arg: &str) {
+ let quote = arg.any(|c| c == ' ' || c == '\t');
+ if quote {
+ cmd.push_char('"');
+ }
+ for uint::range(0, arg.len()) |i| {
+ append_char_at(cmd, arg, i);
+ }
+ if quote {
+ cmd.push_char('"');
+ }
+ }
+
+ fn append_char_at(cmd: &mut ~str, arg: &str, i: uint) {
+ match arg[i] as char {
+ '"' => {
+ // Escape quotes.
+ cmd.push_str("\\\"");
+ }
+ '\\' => {
+ if backslash_run_ends_in_quote(arg, i) {
+ // Double all backslashes that are in runs before quotes.
+ cmd.push_str("\\\\");
+ } else {
+ // Pass other backslashes through unescaped.
+ cmd.push_char('\\');
+ }
+ }
+ c => {
+ cmd.push_char(c);
+ }
+ }
+ }
+
+ fn backslash_run_ends_in_quote(s: &str, mut i: uint) -> bool {
+ while i < s.len() && s[i] as char == '\\' {
+ i += 1;
+ }
+ return i < s.len() && s[i] as char == '"';
+ }
+}
+
+#[cfg(unix)]
+fn spawn_process_internal(prog: &str, args: &[~str],
+ env: &Option<~[(~str,~str)]>,
+ dir: &Option<~str>,
+ in_fd: c_int, out_fd: c_int, err_fd: c_int) -> RunProgramResult {
+
+ use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
+ use libc::funcs::bsd44::getdtablesize;
+
+ mod rustrt {
+ use libc::c_void;
+
+ #[abi = "cdecl"]
+ pub extern {
+ unsafe fn rust_unset_sigprocmask();
+ unsafe fn rust_set_environ(envp: *c_void);
+ }
+ }
+
+ unsafe {
+
+ let pid = fork();
+ if pid < 0 {
+ fail!(fmt!("failure in fork: %s", os::last_os_error()));
+ } else if pid > 0 {
+ return RunProgramResult {pid: pid, handle: ptr::null()};
+ }
+
+ rustrt::rust_unset_sigprocmask();
+
+ if in_fd > 0 && dup2(in_fd, 0) == -1 {
+ fail!(fmt!("failure in dup2(in_fd, 0): %s", os::last_os_error()));
+ }
+ if out_fd > 0 && dup2(out_fd, 1) == -1 {
+ fail!(fmt!("failure in dup2(out_fd, 1): %s", os::last_os_error()));
+ }
+ if err_fd > 0 && dup2(err_fd, 2) == -1 {
+ fail!(fmt!("failure in dup3(err_fd, 2): %s", os::last_os_error()));
+ }
+ // close all other fds
+ for int::range_rev(getdtablesize() as int - 1, 2) |fd| {
+ close(fd as c_int);
+ }
+
+ for dir.each |dir| {
+ do str::as_c_str(*dir) |dirp| {
+ if chdir(dirp) == -1 {
+ fail!(fmt!("failure in chdir: %s", os::last_os_error()));
+ }
+ }
+ }
+
+ do with_envp(env) |envp| {
+ if !envp.is_null() {
+ rustrt::rust_set_environ(envp);
+ }
+ do with_argv(prog, args) |argv| {
+ execvp(*argv, argv);
+ // execvp only returns if an error occurred
+ fail!(fmt!("failure in execvp: %s", os::last_os_error()));
+ }
+ }
+ }
+}
+
+#[cfg(unix)]
fn with_argv<T>(prog: &str, args: &[~str],
cb: &fn(**libc::c_char) -> T) -> T {
let mut argptrs = str::as_c_str(prog, |b| ~[b]);
#[cfg(windows)]
fn with_envp<T>(env: &Option<~[(~str,~str)]>,
- cb: &fn(*c_void) -> T) -> T {
+ cb: &fn(*mut c_void) -> T) -> T {
// On win32 we pass an "environment block" which is not a char**, but
// rather a concatenation of null-terminated k=v\0 sequences, with a final
// \0 to terminate.
blk += ~[0_u8];
vec::as_imm_buf(blk, |p, _len| cb(::cast::transmute(p)))
}
- _ => cb(ptr::null())
+ _ => cb(ptr::mut_null())
}
}
}
+#[cfg(windows)]
fn with_dirp<T>(d: &Option<~str>,
cb: &fn(*libc::c_char) -> T) -> T {
match *d {
pub fn run_program(prog: &str, args: &[~str]) -> int {
let res = spawn_process_internal(prog, args, &None, &None,
0i32, 0i32, 0i32);
- if res.pid == -1 as pid_t { fail!(); }
-
let code = waitpid(res.pid);
free_handle(res.handle);
return code;
pipe_err.out);
unsafe {
- if res.pid == -1 as pid_t { fail!(); }
libc::close(pipe_input.in);
libc::close(pipe_output.out);
libc::close(pipe_err.out);
os::close(pipe_in.in);
os::close(pipe_out.out);
os::close(pipe_err.out);
- if res.pid == -1i32 {
- os::close(pipe_in.out);
- os::close(pipe_out.in);
- os::close(pipe_err.in);
- fail!();
- }
-
os::close(pipe_in.out);
// Spawn two entire schedulers to read both stdout and sterr
#[cfg(windows)]
fn waitpid_os(pid: pid_t) -> int {
- let status = unsafe { rustrt::rust_process_wait(pid) };
- if status < 0 {
- fail!(fmt!("failure in rust_process_wait: %s", os::last_os_error()));
+
+ use libc::types::os::arch::extra::DWORD;
+ use libc::consts::os::extra::{
+ SYNCHRONIZE,
+ PROCESS_QUERY_INFORMATION,
+ FALSE,
+ STILL_ACTIVE,
+ INFINITE,
+ WAIT_FAILED
+ };
+ use libc::funcs::extra::kernel32::{
+ OpenProcess,
+ GetExitCodeProcess,
+ CloseHandle,
+ WaitForSingleObject
+ };
+
+ unsafe {
+
+ let proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD);
+ if proc.is_null() {
+ fail!(fmt!("failure in OpenProcess: %s", os::last_os_error()));
+ }
+
+ loop {
+ let mut status = 0;
+ if GetExitCodeProcess(proc, &mut status) == FALSE {
+ CloseHandle(proc);
+ fail!(fmt!("failure in GetExitCodeProcess: %s", os::last_os_error()));
+ }
+ if status != STILL_ACTIVE {
+ CloseHandle(proc);
+ return status as int;
+ }
+ if WaitForSingleObject(proc, INFINITE) == WAIT_FAILED {
+ CloseHandle(proc);
+ fail!(fmt!("failure in WaitForSingleObject: %s", os::last_os_error()));
+ }
+ }
}
- return status as int;
}
#[cfg(unix)]
use run::{readclose, writeclose};
use run;
+ #[test]
+ #[cfg(windows)]
+ fn test_make_command_line() {
+ assert_eq!(
+ run::make_command_line("prog", [~"aaa", ~"bbb", ~"ccc"]),
+ ~"prog aaa bbb ccc"
+ );
+ assert_eq!(
+ run::make_command_line("C:\\Program Files\\blah\\blah.exe", [~"aaa"]),
+ ~"\"C:\\Program Files\\blah\\blah.exe\" aaa"
+ );
+ assert_eq!(
+ run::make_command_line("C:\\Program Files\\test", [~"aa\"bb"]),
+ ~"\"C:\\Program Files\\test\" aa\\\"bb"
+ );
+ assert_eq!(
+ run::make_command_line("echo", [~"a b c"]),
+ ~"echo \"a b c\""
+ );
+ }
+
// Regression test for memory leaks
#[test]
fn test_leaks() {
#include <crt_externs.h>
#endif
-struct RunProgramResult {
- pid_t pid;
- void* handle;
-};
-
#if defined(__WIN32__)
-#include <process.h>
-#include <io.h>
-
-bool backslash_run_ends_in_quote(char const *c) {
- while (*c == '\\') ++c;
- return *c == '"';
-}
-
-void append_first_char(char *&buf, char const *c) {
- switch (*c) {
-
- case '"':
- // Escape quotes.
- *buf++ = '\\';
- *buf++ = '"';
- break;
-
-
- case '\\':
- if (backslash_run_ends_in_quote(c)) {
- // Double all backslashes that are in runs before quotes.
- *buf++ = '\\';
- *buf++ = '\\';
- } else {
- // Pass other backslashes through unescaped.
- *buf++ = '\\';
- }
- break;
-
- default:
- *buf++ = *c;
- }
+extern "C" CDECL void
+rust_unset_sigprocmask() {
+ // empty stub for windows to keep linker happy
}
-bool contains_whitespace(char const *arg) {
- while (*arg) {
- switch (*arg++) {
- case ' ':
- case '\t':
- return true;
- }
- }
- return false;
-}
-
-void append_arg(char *& buf, char const *arg, bool last) {
- bool quote = contains_whitespace(arg);
- if (quote)
- *buf++ = '"';
- while (*arg)
- append_first_char(buf, arg++);
- if (quote)
- *buf++ = '"';
-
- if (! last) {
- *buf++ = ' ';
- } else {
- *buf++ = '\0';
- }
-}
-
-extern "C" CDECL RunProgramResult
-rust_run_program(const char* argv[],
- void* envp,
- const char* dir,
- int in_fd, int out_fd, int err_fd) {
- STARTUPINFO si;
- ZeroMemory(&si, sizeof(STARTUPINFO));
- si.cb = sizeof(STARTUPINFO);
- si.dwFlags = STARTF_USESTDHANDLES;
-
- RunProgramResult result = {-1, NULL};
-
- HANDLE curproc = GetCurrentProcess();
- HANDLE origStdin = (HANDLE)_get_osfhandle(in_fd ? in_fd : 0);
- if (!DuplicateHandle(curproc, origStdin,
- curproc, &si.hStdInput, 0, 1, DUPLICATE_SAME_ACCESS))
- return result;
- HANDLE origStdout = (HANDLE)_get_osfhandle(out_fd ? out_fd : 1);
- if (!DuplicateHandle(curproc, origStdout,
- curproc, &si.hStdOutput, 0, 1, DUPLICATE_SAME_ACCESS))
- return result;
- HANDLE origStderr = (HANDLE)_get_osfhandle(err_fd ? err_fd : 2);
- if (!DuplicateHandle(curproc, origStderr,
- curproc, &si.hStdError, 0, 1, DUPLICATE_SAME_ACCESS))
- return result;
-
- size_t cmd_len = 0;
- for (const char** arg = argv; *arg; arg++) {
- cmd_len += strlen(*arg);
- cmd_len += 3; // Two quotes plus trailing space or \0
- }
- cmd_len *= 2; // Potentially backslash-escape everything.
-
- char* cmd = (char*)malloc(cmd_len);
- char* pos = cmd;
- for (const char** arg = argv; *arg; arg++) {
- append_arg(pos, *arg, *(arg+1) == NULL);
- }
-
- PROCESS_INFORMATION pi;
- BOOL created = CreateProcess(NULL, cmd, NULL, NULL, TRUE,
- 0, envp, dir, &si, &pi);
-
- CloseHandle(si.hStdInput);
- CloseHandle(si.hStdOutput);
- CloseHandle(si.hStdError);
- free(cmd);
-
- if (!created) {
- return result;
- }
-
- // We close the thread handle because we don't care about keeping the thread id valid,
- // and we aren't keeping the thread handle around to be able to close it later. We don't
- // close the process handle however because we want the process id to stay valid at least
- // until the calling rust code closes the process handle.
- CloseHandle(pi.hThread);
- result.pid = pi.dwProcessId;
- result.handle = pi.hProcess;
- return result;
-}
-
-extern "C" CDECL int
-rust_process_wait(int pid) {
-
- HANDLE proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid);
- if (proc == NULL) {
- return -1;
- }
-
- DWORD status;
- while (true) {
- if (!GetExitCodeProcess(proc, &status)) {
- CloseHandle(proc);
- return -1;
- }
- if (status != STILL_ACTIVE) {
- CloseHandle(proc);
- return (int) status;
- }
- WaitForSingleObject(proc, INFINITE);
- }
+extern "C" CDECL void
+rust_set_environ(void* envp) {
+ // empty stub for windows to keep linker happy
}
#elif defined(__GNUC__)
-#include <sys/file.h>
#include <signal.h>
-#include <sys/ioctl.h>
#include <unistd.h>
-#include <termios.h>
#ifdef __FreeBSD__
extern char **environ;
#endif
-extern "C" CDECL RunProgramResult
-rust_run_program(const char* argv[],
- void* envp,
- const char* dir,
- int in_fd, int out_fd, int err_fd) {
- int pid = fork();
- if (pid != 0) {
- RunProgramResult result = {pid, NULL};
- return result;
- }
-
+extern "C" CDECL void
+rust_unset_sigprocmask() {
+ // this can't be safely converted to rust code because the
+ // representation of sigset_t is platform-dependent
sigset_t sset;
sigemptyset(&sset);
sigprocmask(SIG_SETMASK, &sset, NULL);
+}
- if (in_fd) dup2(in_fd, 0);
- if (out_fd) dup2(out_fd, 1);
- if (err_fd) dup2(err_fd, 2);
- /* Close all other fds. */
- for (int fd = getdtablesize() - 1; fd >= 3; fd--) close(fd);
- if (dir) {
- int result = chdir(dir);
- // FIXME (#2674): need error handling
- assert(!result && "chdir failed");
- }
-
- if (envp) {
+extern "C" CDECL void
+rust_set_environ(void* envp) {
+ // FIXME: this could actually be converted to rust (see issue #2674)
#ifdef __APPLE__
- *_NSGetEnviron() = (char **)envp;
+ *_NSGetEnviron() = (char **) envp;
#else
- environ = (char **)envp;
+ environ = (char **) envp;
#endif
- }
-
- execvp(argv[0], (char * const *)argv);
- exit(1);
-}
-
-extern "C" CDECL int
-rust_process_wait(int pid) {
- // FIXME: stub; exists to placate linker. (#2692)
- return 0;
}
#else
rust_list_dir_wfd_fp_buf
rust_log_console_on
rust_log_console_off
-rust_process_wait
-rust_run_program
+rust_set_environ
+rust_unset_sigprocmask
rust_sched_current_nonlazy_threads
rust_sched_threads
rust_set_exit_status