diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2014-02-06 22:38:05 -0800 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2014-02-16 16:01:03 -0800 |
| commit | 553b7e67d70dbf72dd705616acaa496a20fba765 (patch) | |
| tree | 4274ee5030cea6f05dbbb23f75c1c9eb4e58c2f1 /src/libstd | |
| parent | 13dc521861f6c3be909ba9317fde50f946e9f85d (diff) | |
| download | rust-553b7e67d70dbf72dd705616acaa496a20fba765.tar.gz rust-553b7e67d70dbf72dd705616acaa496a20fba765.zip | |
Allow configuration of uid/gid/detach on processes
This just copies the libuv implementation for libnative which seems reasonable enough (uid/gid fail on windows). Closes #12082
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/io/process.rs | 129 | ||||
| -rw-r--r-- | src/libstd/libc.rs | 6 | ||||
| -rw-r--r-- | src/libstd/run.rs | 34 |
3 files changed, 138 insertions, 31 deletions
diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index b515cd9d31c..6540fcd85d3 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -58,7 +58,21 @@ pub struct ProcessConfig<'a> { /// 0 - stdin /// 1 - stdout /// 2 - stderr - io: &'a [StdioContainer] + io: &'a [StdioContainer], + + /// Sets the child process's user id. This translates to a `setuid` call in + /// the child process. Setting this value on windows will cause the spawn to + /// fail. Failure in the `setuid` call on unix will also cause the spawn to + /// fail. + uid: Option<uint>, + + /// Similar to `uid`, but sets the group id of the child process. This has + /// the same semantics as the `uid` field. + gid: Option<uint>, + + /// If true, the child process is spawned in a detached state. On unix, this + /// means that the child is the leader of a new process group. + detach: bool, } /// Describes what to do with a standard io stream for a child process. @@ -115,6 +129,36 @@ impl ProcessExit { } } +impl<'a> ProcessConfig<'a> { + /// Creates a new configuration with blanks as all of the defaults. This is + /// useful when using functional struct updates: + /// + /// ```rust + /// use std::io::process::{ProcessConfig, Process}; + /// + /// let config = ProcessConfig { + /// program: "/bin/sh", + /// args: &'static [~"-c", ~"echo hello"], + /// .. ProcessConfig::new() + /// }; + /// + /// let p = Process::new(config); + /// ``` + /// + pub fn new() -> ProcessConfig<'static> { + ProcessConfig { + program: "", + args: &'static [], + env: None, + cwd: None, + io: &'static [], + uid: None, + gid: None, + detach: false, + } + } +} + impl Process { /// Creates a new pipe initialized, but not bound to any particular /// source/destination @@ -175,13 +219,10 @@ mod tests { // FIXME(#10380) #[cfg(unix, not(target_os="android"))] iotest!(fn smoke() { - let io = ~[]; let args = ProcessConfig { program: "/bin/sh", args: &[~"-c", ~"true"], - env: None, - cwd: None, - io: io, + .. ProcessConfig::new() }; let p = Process::new(args); assert!(p.is_ok()); @@ -192,13 +233,9 @@ mod tests { // FIXME(#10380) #[cfg(unix, not(target_os="android"))] iotest!(fn smoke_failure() { - let io = ~[]; let args = ProcessConfig { program: "if-this-is-a-binary-then-the-world-has-ended", - args: &[], - env: None, - cwd: None, - io: io, + .. ProcessConfig::new() }; match Process::new(args) { Ok(..) => fail!(), @@ -209,13 +246,10 @@ mod tests { // FIXME(#10380) #[cfg(unix, not(target_os="android"))] iotest!(fn exit_reported_right() { - let io = ~[]; let args = ProcessConfig { program: "/bin/sh", args: &[~"-c", ~"exit 1"], - env: None, - cwd: None, - io: io, + .. ProcessConfig::new() }; let p = Process::new(args); assert!(p.is_ok()); @@ -225,13 +259,10 @@ mod tests { #[cfg(unix, not(target_os="android"))] iotest!(fn signal_reported_right() { - let io = ~[]; let args = ProcessConfig { program: "/bin/sh", args: &[~"-c", ~"kill -1 $$"], - env: None, - cwd: None, - io: io, + .. ProcessConfig::new() }; let p = Process::new(args); assert!(p.is_ok()); @@ -264,9 +295,8 @@ mod tests { let args = ProcessConfig { program: "/bin/sh", args: &[~"-c", ~"echo foobar"], - env: None, - cwd: None, io: io, + .. ProcessConfig::new() }; assert_eq!(run_output(args), ~"foobar\n"); }) @@ -279,9 +309,9 @@ mod tests { let args = ProcessConfig { program: "/bin/sh", args: &[~"-c", ~"pwd"], - env: None, cwd: cwd, io: io, + .. ProcessConfig::new() }; assert_eq!(run_output(args), ~"/\n"); }) @@ -294,9 +324,8 @@ mod tests { let args = ProcessConfig { program: "/bin/sh", args: &[~"-c", ~"read line; echo $line"], - env: None, - cwd: None, io: io, + .. ProcessConfig::new() }; let mut p = Process::new(args).unwrap(); p.io[0].get_mut_ref().write("foobar".as_bytes()).unwrap(); @@ -306,4 +335,58 @@ mod tests { assert_eq!(out, ~"foobar\n"); }) + // FIXME(#10380) + #[cfg(unix, not(target_os="android"))] + iotest!(fn detach_works() { + let args = ProcessConfig { + program: "/bin/sh", + args: &[~"-c", ~"true"], + detach: true, + .. ProcessConfig::new() + }; + let mut p = Process::new(args).unwrap(); + assert!(p.wait().success()); + }) + + #[cfg(windows)] + iotest!(fn uid_fails_on_windows() { + let args = ProcessConfig { + program: "test", + uid: Some(10), + .. ProcessConfig::new() + }; + assert!(Process::new(args).is_err()); + }) + + // FIXME(#10380) + #[cfg(unix, not(target_os="android"))] + iotest!(fn uid_works() { + use libc; + let args = ProcessConfig { + program: "/bin/sh", + args: &[~"-c", ~"true"], + uid: Some(unsafe { libc::getuid() as uint }), + gid: Some(unsafe { libc::getgid() as uint }), + .. ProcessConfig::new() + }; + let mut p = Process::new(args).unwrap(); + assert!(p.wait().success()); + }) + + // FIXME(#10380) + #[cfg(unix, not(target_os="android"))] + iotest!(fn uid_to_root_fails() { + use libc; + + // if we're already root, this isn't a valid test. Most of the bots run + // as non-root though (android is an exception). + if unsafe { libc::getuid() == 0 } { return } + let args = ProcessConfig { + program: "/bin/ls", + uid: Some(0), + gid: Some(0), + .. ProcessConfig::new() + }; + assert!(Process::new(args).is_err()); + }) } diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 39383f99392..7dc4c692f63 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -159,7 +159,7 @@ pub use libc::funcs::c95::stdio::{fread, freopen, fseek, fsetpos, ftell}; pub use libc::funcs::c95::stdio::{fwrite, perror, puts, remove, rewind}; pub use libc::funcs::c95::stdio::{setbuf, setvbuf, tmpfile, ungetc}; -pub use libc::funcs::c95::stdlib::{abs, atof, atoi, calloc, exit}; +pub use libc::funcs::c95::stdlib::{abs, atof, atoi, calloc, exit, _exit}; pub use libc::funcs::c95::stdlib::{free, getenv, labs, malloc, rand}; pub use libc::funcs::c95::stdlib::{realloc, srand, strtod, strtol}; pub use libc::funcs::c95::stdlib::{strtoul, system}; @@ -1769,6 +1769,9 @@ pub mod consts { pub static MAX_PROTOCOL_CHAIN: DWORD = 7; pub static WSAPROTOCOL_LEN: DWORD = 255; pub static INVALID_SOCKET: DWORD = !0; + + pub static DETACHED_PROCESS: DWORD = 0x00000008; + pub static CREATE_NEW_PROCESS_GROUP: DWORD = 0x00000200; } pub mod sysconf { } @@ -3340,6 +3343,7 @@ pub mod funcs { pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; pub fn free(p: *mut c_void); pub fn exit(status: c_int) -> !; + pub fn _exit(status: c_int) -> !; // Omitted: atexit. pub fn system(s: *c_char) -> c_int; pub fn getenv(s: *c_char) -> *c_char; diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 6f684f23d47..9ea8f6447dd 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -88,6 +88,20 @@ pub struct ProcessOptions<'a> { * and Process.error() will fail. */ err_fd: Option<c_int>, + + /// The uid to assume for the child process. For more information, see the + /// documentation in `io::process::ProcessConfig` about this field. + uid: Option<uint>, + + /// The gid to assume for the child process. For more information, see the + /// documentation in `io::process::ProcessConfig` about this field. + gid: Option<uint>, + + /// Flag as to whether the child process will be the leader of a new process + /// group or not. This allows the parent process to exit while the child is + /// still running. For more information, see the documentation in + /// `io::process::ProcessConfig` about this field. + detach: bool, } impl <'a> ProcessOptions<'a> { @@ -99,6 +113,9 @@ impl <'a> ProcessOptions<'a> { in_fd: None, out_fd: None, err_fd: None, + uid: None, + gid: None, + detach: false, } } } @@ -128,7 +145,9 @@ impl Process { */ pub fn new(prog: &str, args: &[~str], options: ProcessOptions) -> io::IoResult<Process> { - let ProcessOptions { env, dir, in_fd, out_fd, err_fd } = options; + let ProcessOptions { + env, dir, in_fd, out_fd, err_fd, uid, gid, detach + } = options; let env = env.as_ref().map(|a| a.as_slice()); let cwd = dir.as_ref().map(|a| a.as_str().unwrap()); fn rtify(fd: Option<c_int>, input: bool) -> process::StdioContainer { @@ -145,6 +164,9 @@ impl Process { env: env, cwd: cwd, io: rtio, + uid: uid, + gid: gid, + detach: detach, }; process::Process::new(rtconfig).map(|p| Process { inner: p }) } @@ -302,11 +324,10 @@ impl Process { */ pub fn process_status(prog: &str, args: &[~str]) -> io::IoResult<ProcessExit> { Process::new(prog, args, ProcessOptions { - env: None, - dir: None, in_fd: Some(unsafe { libc::dup(libc::STDIN_FILENO) }), out_fd: Some(unsafe { libc::dup(libc::STDOUT_FILENO) }), - err_fd: Some(unsafe { libc::dup(libc::STDERR_FILENO) }) + err_fd: Some(unsafe { libc::dup(libc::STDERR_FILENO) }), + .. ProcessOptions::new() }).map(|mut p| p.finish()) } @@ -396,11 +417,10 @@ mod tests { let pipe_err = os::pipe(); let mut process = run::Process::new("cat", [], run::ProcessOptions { - dir: None, - env: None, in_fd: Some(pipe_in.input), out_fd: Some(pipe_out.out), - err_fd: Some(pipe_err.out) + err_fd: Some(pipe_err.out), + .. run::ProcessOptions::new() }).unwrap(); os::close(pipe_in.input as int); |
