(index<- )        ./libstd/rt/io/process.rs

   1  // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  //! Bindings for executing child processes
  12  
  13  use prelude::*;
  14  
  15  use libc;
  16  use rt::io;
  17  use rt::io::io_error;
  18  use rt::local::Local;
  19  use rt::rtio::{RtioProcess, RtioProcessObject, IoFactoryObject, IoFactory};
  20  
  21  // windows values don't matter as long as they're at least one of unix's
  22  // TERM/KILL/INT signals
  23  #[cfg(windows)] pub static PleaseExitSignal: int = 15;
  24  #[cfg(windows)] pub static MustDieSignal: int = 9;
  25  #[cfg(not(windows))] pub static PleaseExitSignal: int = libc::SIGTERM as int;
  26  #[cfg(not(windows))] pub static MustDieSignal: int = libc::SIGKILL as int;
  27  
  28  pub struct Process {
  29      priv handle: ~RtioProcessObject,
  30      io: ~[Option<io::PipeStream>],
  31  }
  32  
  33  /// This configuration describes how a new process should be spawned. This is
  34  /// translated to libuv's own configuration
  35  pub struct ProcessConfig<'self> {
  36      /// Path to the program to run
  37      program: &'self str,
  38  
  39      /// Arguments to pass to the program (doesn't include the program itself)
  40      args: &'self [~str],
  41  
  42      /// Optional environment to specify for the program. If this is None, then
  43      /// it will inherit the current process's environment.
  44      env: Option<&'self [(~str, ~str)]>,
  45  
  46      /// Optional working directory for the new process. If this is None, then
  47      /// the current directory of the running process is inherited.
  48      cwd: Option<&'self str>,
  49  
  50      /// Any number of streams/file descriptors/pipes may be attached to this
  51      /// process. This list enumerates the file descriptors and such for the
  52      /// process to be spawned, and the file descriptors inherited will start at
  53      /// 0 and go to the length of this array.
  54      ///
  55      /// Standard file descriptors are:
  56      ///
  57      ///     0 - stdin
  58      ///     1 - stdout
  59      ///     2 - stderr
  60      io: ~[StdioContainer]
  61  }
  62  
  63  /// Describes what to do with a standard io stream for a child process.
  64  pub enum StdioContainer {
  65      /// This stream will be ignored. This is the equivalent of attaching the
  66      /// stream to `/dev/null`
  67      Ignored,
  68  
  69      /// The specified file descriptor is inherited for the stream which it is
  70      /// specified for.
  71      InheritFd(libc::c_int),
  72  
  73      // XXX: these two shouldn't have libuv-specific implementation details
  74  
  75      /// The specified libuv stream is inherited for the corresponding file
  76      /// descriptor it is assigned to.
  77      // XXX: this needs to be thought out more.
  78      //InheritStream(uv::net::StreamWatcher),
  79  
  80      /// Creates a pipe for the specified file descriptor which will be directed
  81      /// into the previously-initialized pipe passed in.
  82      ///
  83      /// The first boolean argument is whether the pipe is readable, and the
  84      /// second is whether it is writable. These properties are from the view of
  85      /// the *child* process, not the parent process.
  86      CreatePipe(io::UnboundPipeStream,
  87                 bool /* readable */,
  88                 bool /* writable */),
  89  }
  90  
  91  impl Process {
  92      /// Creates a new pipe initialized, but not bound to any particular
  93      /// source/destination
  94      pub fn new(configProcessConfig) -> Option<Process> {
  95          let process = unsafe {
  96              let io*mut IoFactoryObject = Local::unsafe_borrow();
  97              (*io).spawn(config)
  98          };
  99          match process {
 100              Ok((p, io)) => Some(Process{
 101                  handle: p,
 102                  io: io.move_iter().map(|p|
 103                      p.map(|p| io::PipeStream::bind(p))
 104                  ).collect()
 105              }),
 106              Err(ioerr) => {
 107                  io_error::cond.raise(ioerr);
 108                  None
 109              }
 110          }
 111      }
 112  
 113      /// Returns the process id of this child process
 114      pub fn id(&self) -> libc::pid_t { self.handle.id() }
 115  
 116      /// Sends the specified signal to the child process, returning whether the
 117      /// signal could be delivered or not.
 118      ///
 119      /// Note that this is purely a wrapper around libuv's `uv_process_kill`
 120      /// function.
 121      ///
 122      /// If the signal delivery fails, then the `io_error` condition is raised on
 123      pub fn signal(&mut self, signalint) {
 124          match self.handle.kill(signal) {
 125              Ok(()) => {}
 126              Err(err) => {
 127                  io_error::cond.raise(err)
 128              }
 129          }
 130      }
 131  
 132      /// Wait for the child to exit completely, returning the status that it
 133      /// exited with. This function will continue to have the same return value
 134      /// after it has been called at least once.
 135      pub fn wait(&mut self) -> int { self.handle.wait() }
 136  }
 137  
 138  impl Drop for Process {
 139      fn drop(&mut self) {
 140          // Close all I/O before exiting to ensure that the child doesn't wait
 141          // forever to print some text or something similar.
 142          for _ in range(0, self.io.len()) {
 143              self.io.pop();
 144          }
 145  
 146          self.wait();
 147      }
 148  }
 149  
 150  // Tests for this module can be found in the rtio-processes run-pass test, along
 151  // with the justification for why it's not located here.