1 #[cfg(unix)] 2 mod os { 3 pub const NULL_DEVICE: &str = "/dev/null"; 4 pub const SHELL: [&str; 2] = ["sh", "-c"]; 5 } 6 7 #[cfg(windows)] 8 mod os { 9 pub const NULL_DEVICE: &str = "nul"; 10 pub const SHELL: [&str; 2] = ["cmd.exe", "/c"]; 11 } 12 13 pub use self::exec::{CaptureData, Exec, NullFile}; 14 pub use self::os::*; 15 pub use self::pipeline::Pipeline; 16 17 #[cfg(unix)] 18 pub use exec::unix; 19 20 mod exec { 21 use std::ffi::{OsStr, OsString}; 22 use std::fmt; 23 use std::fs::{File, OpenOptions}; 24 use std::io::{self, Read, Write}; 25 use std::ops::BitOr; 26 use std::path::Path; 27 28 use crate::communicate::Communicator; 29 use crate::os_common::ExitStatus; 30 use crate::popen::{Popen, PopenConfig, Redirection, Result as PopenResult}; 31 32 use super::os::*; 33 use super::Pipeline; 34 35 /// A builder for [`Popen`] instances, providing control and 36 /// convenience methods. 37 /// 38 /// `Exec` provides a builder API for [`Popen::create`], and 39 /// includes convenience methods for capturing the output, and for 40 /// connecting subprocesses into pipelines. 41 /// 42 /// # Examples 43 /// 44 /// Execute an external command and wait for it to complete: 45 /// 46 /// ```no_run 47 /// # use subprocess::*; 48 /// # fn dummy() -> Result<()> { 49 /// # let dirname = "some_dir"; 50 /// let exit_status = Exec::cmd("umount").arg(dirname).join()?; 51 /// # Ok(()) 52 /// # } 53 /// ``` 54 /// 55 /// Execute the command using the OS shell, like C's `system`: 56 /// 57 /// ```no_run 58 /// # use subprocess::*; 59 /// # fn dummy() -> Result<()> { 60 /// Exec::shell("shutdown -h now").join()?; 61 /// # Ok(()) 62 /// # } 63 /// ``` 64 /// 65 /// Start a subprocess and obtain its output as a `Read` trait object, 66 /// like C's `popen`: 67 /// 68 /// ``` 69 /// # use subprocess::*; 70 /// # fn dummy() -> Result<()> { 71 /// let stream = Exec::cmd("ls").stream_stdout()?; 72 /// // call stream.read_to_string, construct io::BufReader(stream), etc. 73 /// # Ok(()) 74 /// # } 75 /// ``` 76 /// 77 /// Capture the output of a command: 78 /// 79 /// ``` 80 /// # use subprocess::*; 81 /// # fn dummy() -> Result<()> { 82 /// let out = Exec::cmd("ls") 83 /// .stdout(Redirection::Pipe) 84 /// .capture()? 85 /// .stdout_str(); 86 /// # Ok(()) 87 /// # } 88 /// ``` 89 /// 90 /// Redirect errors to standard output, and capture both in a single stream: 91 /// 92 /// ``` 93 /// # use subprocess::*; 94 /// # fn dummy() -> Result<()> { 95 /// let out_and_err = Exec::cmd("ls") 96 /// .stdout(Redirection::Pipe) 97 /// .stderr(Redirection::Merge) 98 /// .capture()? 99 /// .stdout_str(); 100 /// # Ok(()) 101 /// # } 102 /// ``` 103 /// 104 /// Provide input to the command and read its output: 105 /// 106 /// ``` 107 /// # use subprocess::*; 108 /// # fn dummy() -> Result<()> { 109 /// let out = Exec::cmd("sort") 110 /// .stdin("b\nc\na\n") 111 /// .stdout(Redirection::Pipe) 112 /// .capture()? 113 /// .stdout_str(); 114 /// assert!(out == "a\nb\nc\n"); 115 /// # Ok(()) 116 /// # } 117 /// ``` 118 /// 119 /// [`Popen`]: struct.Popen.html 120 /// [`Popen::create`]: struct.Popen.html#method.create 121 122 #[must_use] 123 pub struct Exec { 124 command: OsString, 125 args: Vec<OsString>, 126 config: PopenConfig, 127 stdin_data: Option<Vec<u8>>, 128 } 129 130 impl Exec { 131 /// Constructs a new `Exec`, configured to run `command`. 132 /// 133 /// The command will be run directly in the OS, without an 134 /// intervening shell. To run it through a shell, use 135 /// [`Exec::shell`] instead. 136 /// 137 /// By default, the command will be run without arguments, and 138 /// none of the standard streams will be modified. 139 /// 140 /// [`Exec::shell`]: struct.Exec.html#method.shell cmd(command: impl AsRef<OsStr>) -> Exec141 pub fn cmd(command: impl AsRef<OsStr>) -> Exec { 142 Exec { 143 command: command.as_ref().to_owned(), 144 args: vec![], 145 config: PopenConfig::default(), 146 stdin_data: None, 147 } 148 } 149 150 /// Constructs a new `Exec`, configured to run `cmdstr` with 151 /// the system shell. 152 /// 153 /// `subprocess` never spawns shells without an explicit 154 /// request. This command requests the shell to be used; on 155 /// Unix-like systems, this is equivalent to 156 /// `Exec::cmd("sh").arg("-c").arg(cmdstr)`. On Windows, it 157 /// runs `Exec::cmd("cmd.exe").arg("/c")`. 158 /// 159 /// `shell` is useful for porting code that uses the C 160 /// `system` function, which also spawns a shell. 161 /// 162 /// When invoking this function, be careful not to interpolate 163 /// arguments into the string run by the shell, such as 164 /// `Exec::shell(format!("sort {}", filename))`. Such code is 165 /// prone to errors and, if `filename` comes from an untrusted 166 /// source, to shell injection attacks. Instead, use 167 /// `Exec::cmd("sort").arg(filename)`. shell(cmdstr: impl AsRef<OsStr>) -> Exec168 pub fn shell(cmdstr: impl AsRef<OsStr>) -> Exec { 169 Exec::cmd(SHELL[0]).args(&SHELL[1..]).arg(cmdstr) 170 } 171 172 /// Appends `arg` to argument list. arg(mut self, arg: impl AsRef<OsStr>) -> Exec173 pub fn arg(mut self, arg: impl AsRef<OsStr>) -> Exec { 174 self.args.push(arg.as_ref().to_owned()); 175 self 176 } 177 178 /// Extends the argument list with `args`. args(mut self, args: &[impl AsRef<OsStr>]) -> Exec179 pub fn args(mut self, args: &[impl AsRef<OsStr>]) -> Exec { 180 self.args.extend(args.iter().map(|x| x.as_ref().to_owned())); 181 self 182 } 183 184 /// Specifies that the process is initially detached. 185 /// 186 /// A detached process means that we will not wait for the 187 /// process to finish when the object that owns it goes out of 188 /// scope. detached(mut self) -> Exec189 pub fn detached(mut self) -> Exec { 190 self.config.detached = true; 191 self 192 } 193 ensure_env(&mut self)194 fn ensure_env(&mut self) { 195 if self.config.env.is_none() { 196 self.config.env = Some(PopenConfig::current_env()); 197 } 198 } 199 200 /// Clears the environment of the subprocess. 201 /// 202 /// When this is invoked, the subprocess will not inherit the 203 /// environment of this process. env_clear(mut self) -> Exec204 pub fn env_clear(mut self) -> Exec { 205 self.config.env = Some(vec![]); 206 self 207 } 208 209 /// Sets an environment variable in the child process. 210 /// 211 /// If the same variable is set more than once, the last value 212 /// is used. 213 /// 214 /// Other environment variables are by default inherited from 215 /// the current process. If this is undesirable, call 216 /// `env_clear` first. env(mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> Exec217 pub fn env(mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> Exec { 218 self.ensure_env(); 219 self.config 220 .env 221 .as_mut() 222 .unwrap() 223 .push((key.as_ref().to_owned(), value.as_ref().to_owned())); 224 self 225 } 226 227 /// Sets multiple environment variables in the child process. 228 /// 229 /// The keys and values of the variables are specified by the 230 /// slice. If the same variable is set more than once, the 231 /// last value is used. 232 /// 233 /// Other environment variables are by default inherited from 234 /// the current process. If this is undesirable, call 235 /// `env_clear` first. env_extend(mut self, vars: &[(impl AsRef<OsStr>, impl AsRef<OsStr>)]) -> Exec236 pub fn env_extend(mut self, vars: &[(impl AsRef<OsStr>, impl AsRef<OsStr>)]) -> Exec { 237 self.ensure_env(); 238 { 239 let envvec = self.config.env.as_mut().unwrap(); 240 for &(ref k, ref v) in vars { 241 envvec.push((k.as_ref().to_owned(), v.as_ref().to_owned())); 242 } 243 } 244 self 245 } 246 247 /// Removes an environment variable from the child process. 248 /// 249 /// Other environment variables are inherited by default. env_remove(mut self, key: impl AsRef<OsStr>) -> Exec250 pub fn env_remove(mut self, key: impl AsRef<OsStr>) -> Exec { 251 self.ensure_env(); 252 self.config 253 .env 254 .as_mut() 255 .unwrap() 256 .retain(|&(ref k, ref _v)| k != key.as_ref()); 257 self 258 } 259 260 /// Specifies the current working directory of the child process. 261 /// 262 /// If unspecified, the current working directory is inherited 263 /// from the parent. cwd(mut self, dir: impl AsRef<Path>) -> Exec264 pub fn cwd(mut self, dir: impl AsRef<Path>) -> Exec { 265 self.config.cwd = Some(dir.as_ref().as_os_str().to_owned()); 266 self 267 } 268 269 /// Specifies how to set up the standard input of the child process. 270 /// 271 /// Argument can be: 272 /// 273 /// * a [`Redirection`]; 274 /// * a `File`, which is a shorthand for `Redirection::File(file)`; 275 /// * a `Vec<u8>` or `&str`, which will set up a `Redirection::Pipe` 276 /// for stdin, making sure that `capture` feeds that data into the 277 /// standard input of the subprocess; 278 /// * [`NullFile`], which will redirect the standard input to read from 279 /// `/dev/null`. 280 /// 281 /// [`Redirection`]: enum.Redirection.html 282 /// [`NullFile`]: struct.NullFile.html stdin(mut self, stdin: impl Into<InputRedirection>) -> Exec283 pub fn stdin(mut self, stdin: impl Into<InputRedirection>) -> Exec { 284 match (&self.config.stdin, stdin.into()) { 285 (&Redirection::None, InputRedirection::AsRedirection(new)) => { 286 self.config.stdin = new 287 } 288 (&Redirection::Pipe, InputRedirection::AsRedirection(Redirection::Pipe)) => (), 289 (&Redirection::None, InputRedirection::FeedData(data)) => { 290 self.config.stdin = Redirection::Pipe; 291 self.stdin_data = Some(data); 292 } 293 (_, _) => panic!("stdin is already set"), 294 } 295 self 296 } 297 298 /// Specifies how to set up the standard output of the child process. 299 /// 300 /// Argument can be: 301 /// 302 /// * a [`Redirection`]; 303 /// * a `File`, which is a shorthand for `Redirection::File(file)`; 304 /// * [`NullFile`], which will redirect the standard output to go to 305 /// `/dev/null`. 306 /// 307 /// [`Redirection`]: enum.Redirection.html 308 /// [`NullFile`]: struct.NullFile.html stdout(mut self, stdout: impl Into<OutputRedirection>) -> Exec309 pub fn stdout(mut self, stdout: impl Into<OutputRedirection>) -> Exec { 310 match (&self.config.stdout, stdout.into().into_redirection()) { 311 (&Redirection::None, new) => self.config.stdout = new, 312 (&Redirection::Pipe, Redirection::Pipe) => (), 313 (_, _) => panic!("stdout is already set"), 314 } 315 self 316 } 317 318 /// Specifies how to set up the standard error of the child process. 319 /// 320 /// Argument can be: 321 /// 322 /// * a [`Redirection`]; 323 /// * a `File`, which is a shorthand for `Redirection::File(file)`; 324 /// * [`NullFile`], which will redirect the standard error to go to 325 /// `/dev/null`. 326 /// 327 /// [`Redirection`]: enum.Redirection.html 328 /// [`NullFile`]: struct.NullFile.html stderr(mut self, stderr: impl Into<OutputRedirection>) -> Exec329 pub fn stderr(mut self, stderr: impl Into<OutputRedirection>) -> Exec { 330 match (&self.config.stderr, stderr.into().into_redirection()) { 331 (&Redirection::None, new) => self.config.stderr = new, 332 (&Redirection::Pipe, Redirection::Pipe) => (), 333 (_, _) => panic!("stderr is already set"), 334 } 335 self 336 } 337 check_no_stdin_data(&self, meth: &str)338 fn check_no_stdin_data(&self, meth: &str) { 339 if self.stdin_data.is_some() { 340 panic!("{} called with input data specified", meth); 341 } 342 } 343 344 // Terminators 345 346 /// Starts the process, returning a `Popen` for the running process. popen(mut self) -> PopenResult<Popen>347 pub fn popen(mut self) -> PopenResult<Popen> { 348 self.check_no_stdin_data("popen"); 349 self.args.insert(0, self.command); 350 let p = Popen::create(&self.args, self.config)?; 351 Ok(p) 352 } 353 354 /// Starts the process, waits for it to finish, and returns 355 /// the exit status. 356 /// 357 /// This method will wait for as long as necessary for the process to 358 /// finish. If a timeout is needed, use 359 /// `<...>.detached().popen()?.wait_timeout(...)` instead. join(self) -> PopenResult<ExitStatus>360 pub fn join(self) -> PopenResult<ExitStatus> { 361 self.check_no_stdin_data("join"); 362 self.popen()?.wait() 363 } 364 365 /// Starts the process and returns a value implementing the `Read` 366 /// trait that reads from the standard output of the child process. 367 /// 368 /// This will automatically set up 369 /// `stdout(Redirection::Pipe)`, so it is not necessary to do 370 /// that beforehand. 371 /// 372 /// When the trait object is dropped, it will wait for the 373 /// process to finish. If this is undesirable, use 374 /// `detached()`. stream_stdout(self) -> PopenResult<impl Read>375 pub fn stream_stdout(self) -> PopenResult<impl Read> { 376 self.check_no_stdin_data("stream_stdout"); 377 let p = self.stdout(Redirection::Pipe).popen()?; 378 Ok(ReadOutAdapter(p)) 379 } 380 381 /// Starts the process and returns a value implementing the `Read` 382 /// trait that reads from the standard error of the child process. 383 /// 384 /// This will automatically set up 385 /// `stderr(Redirection::Pipe)`, so it is not necessary to do 386 /// that beforehand. 387 /// 388 /// When the trait object is dropped, it will wait for the 389 /// process to finish. If this is undesirable, use 390 /// `detached()`. stream_stderr(self) -> PopenResult<impl Read>391 pub fn stream_stderr(self) -> PopenResult<impl Read> { 392 self.check_no_stdin_data("stream_stderr"); 393 let p = self.stderr(Redirection::Pipe).popen()?; 394 Ok(ReadErrAdapter(p)) 395 } 396 397 /// Starts the process and returns a value implementing the `Write` 398 /// trait that writes to the standard input of the child process. 399 /// 400 /// This will automatically set up `stdin(Redirection::Pipe)`, 401 /// so it is not necessary to do that beforehand. 402 /// 403 /// When the trait object is dropped, it will wait for the 404 /// process to finish. If this is undesirable, use 405 /// `detached()`. stream_stdin(self) -> PopenResult<impl Write>406 pub fn stream_stdin(self) -> PopenResult<impl Write> { 407 self.check_no_stdin_data("stream_stdin"); 408 let p = self.stdin(Redirection::Pipe).popen()?; 409 Ok(WriteAdapter(p)) 410 } 411 setup_communicate(mut self) -> PopenResult<(Communicator, Popen)>412 fn setup_communicate(mut self) -> PopenResult<(Communicator, Popen)> { 413 let stdin_data = self.stdin_data.take(); 414 if let (&Redirection::None, &Redirection::None) = 415 (&self.config.stdout, &self.config.stderr) 416 { 417 self = self.stdout(Redirection::Pipe); 418 } 419 let mut p = self.popen()?; 420 421 Ok((p.communicate_start(stdin_data), p)) 422 } 423 424 /// Starts the process and returns a `Communicator` handle. 425 /// 426 /// This is a lower-level API that offers more choice in how 427 /// communication is performed, such as read size limit and timeout, 428 /// equivalent to [`Popen::communicate`]. 429 /// 430 /// Unlike `capture()`, this method doesn't wait for the process to 431 /// finish, effectively detaching it. 432 /// 433 /// [`Popen::communicate`]: struct.Popen.html#method.communicate communicate(self) -> PopenResult<Communicator>434 pub fn communicate(self) -> PopenResult<Communicator> { 435 let comm = self.detached().setup_communicate()?.0; 436 Ok(comm) 437 } 438 439 /// Starts the process, collects its output, and waits for it 440 /// to finish. 441 /// 442 /// The return value provides the standard output and standard 443 /// error as bytes or optionally strings, as well as the exit 444 /// status. 445 /// 446 /// Unlike `Popen::communicate`, this method actually waits 447 /// for the process to finish, rather than simply waiting for 448 /// its standard streams to close. If this is undesirable, 449 /// use `detached()`. capture(self) -> PopenResult<CaptureData>450 pub fn capture(self) -> PopenResult<CaptureData> { 451 let (mut comm, mut p) = self.setup_communicate()?; 452 let (maybe_out, maybe_err) = comm.read()?; 453 Ok(CaptureData { 454 stdout: maybe_out.unwrap_or_else(Vec::new), 455 stderr: maybe_err.unwrap_or_else(Vec::new), 456 exit_status: p.wait()?, 457 }) 458 } 459 460 /// Show Exec as command-line string quoted in the Unix style. to_cmdline_lossy(&self) -> String461 pub fn to_cmdline_lossy(&self) -> String { 462 fn nice_char(c: char) -> bool { 463 match c { 464 '-' | '_' | '.' | ',' | '/' => true, 465 c if c.is_ascii_alphanumeric() => true, 466 _ => false, 467 } 468 } 469 fn write_quoted(out: &mut String, s: &str) { 470 if !s.chars().all(nice_char) { 471 out.push_str(&format!("'{}'", s.replace("'", r#"'\''"#))); 472 } else { 473 out.push_str(s); 474 } 475 } 476 let mut out = String::new(); 477 write_quoted(&mut out, &self.command.to_string_lossy()); 478 for arg in &self.args { 479 out.push(' '); 480 write_quoted(&mut out, &arg.to_string_lossy()); 481 } 482 out 483 } 484 } 485 486 impl Clone for Exec { 487 /// Returns a copy of the value. 488 /// 489 /// This method is guaranteed not to fail as long as none of 490 /// the `Redirection` values contain a `Redirection::File` 491 /// variant. If a redirection to `File` is present, cloning 492 /// that field will use `File::try_clone` method, which 493 /// duplicates a file descriptor and can (but is not likely 494 /// to) fail. In that scenario, `Exec::clone` panics. clone(&self) -> Exec495 fn clone(&self) -> Exec { 496 Exec { 497 command: self.command.clone(), 498 args: self.args.clone(), 499 config: self.config.try_clone().unwrap(), 500 stdin_data: self.stdin_data.as_ref().cloned(), 501 } 502 } 503 } 504 505 impl BitOr for Exec { 506 type Output = Pipeline; 507 508 /// Create a `Pipeline` from `self` and `rhs`. bitor(self, rhs: Exec) -> Pipeline509 fn bitor(self, rhs: Exec) -> Pipeline { 510 Pipeline::new(self, rhs) 511 } 512 } 513 514 impl fmt::Debug for Exec { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result515 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 516 write!(f, "Exec {{ {} }}", self.to_cmdline_lossy()) 517 } 518 } 519 520 #[derive(Debug)] 521 struct ReadOutAdapter(Popen); 522 523 impl Read for ReadOutAdapter { read(&mut self, buf: &mut [u8]) -> io::Result<usize>524 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { 525 self.0.stdout.as_mut().unwrap().read(buf) 526 } 527 } 528 529 #[derive(Debug)] 530 struct ReadErrAdapter(Popen); 531 532 impl Read for ReadErrAdapter { read(&mut self, buf: &mut [u8]) -> io::Result<usize>533 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { 534 self.0.stderr.as_mut().unwrap().read(buf) 535 } 536 } 537 538 #[derive(Debug)] 539 struct WriteAdapter(Popen); 540 541 impl Write for WriteAdapter { write(&mut self, buf: &[u8]) -> io::Result<usize>542 fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 543 self.0.stdin.as_mut().unwrap().write(buf) 544 } flush(&mut self) -> io::Result<()>545 fn flush(&mut self) -> io::Result<()> { 546 self.0.stdin.as_mut().unwrap().flush() 547 } 548 } 549 550 // We must implement Drop in order to close the stream. The typical 551 // use case for stream_stdin() is a process that reads something from 552 // stdin. WriteAdapter going out of scope invokes Popen::drop(), 553 // which waits for the process to exit. Without closing stdin, this 554 // deadlocks because the child process hangs reading its stdin. 555 556 impl Drop for WriteAdapter { drop(&mut self)557 fn drop(&mut self) { 558 self.0.stdin.take(); 559 } 560 } 561 562 /// Data captured by [`Exec::capture`] and [`Pipeline::capture`]. 563 /// 564 /// [`Exec::capture`]: struct.Exec.html#method.capture 565 /// [`Pipeline::capture`]: struct.Pipeline.html#method.capture 566 pub struct CaptureData { 567 /// Standard output as bytes. 568 pub stdout: Vec<u8>, 569 /// Standard error as bytes. 570 pub stderr: Vec<u8>, 571 /// Exit status. 572 pub exit_status: ExitStatus, 573 } 574 575 impl CaptureData { 576 /// Returns the standard output as string, converted from bytes using 577 /// `String::from_utf8_lossy`. stdout_str(&self) -> String578 pub fn stdout_str(&self) -> String { 579 String::from_utf8_lossy(&self.stdout).into_owned() 580 } 581 582 /// Returns the standard error as string, converted from bytes using 583 /// `String::from_utf8_lossy`. stderr_str(&self) -> String584 pub fn stderr_str(&self) -> String { 585 String::from_utf8_lossy(&self.stderr).into_owned() 586 } 587 588 /// True if the exit status of the process or pipeline is 0. success(&self) -> bool589 pub fn success(&self) -> bool { 590 self.exit_status.success() 591 } 592 } 593 594 pub enum InputRedirection { 595 AsRedirection(Redirection), 596 FeedData(Vec<u8>), 597 } 598 599 impl From<Redirection> for InputRedirection { from(r: Redirection) -> Self600 fn from(r: Redirection) -> Self { 601 if let Redirection::Merge = r { 602 panic!("Redirection::Merge is only allowed for output streams"); 603 } 604 InputRedirection::AsRedirection(r) 605 } 606 } 607 608 impl From<File> for InputRedirection { from(f: File) -> Self609 fn from(f: File) -> Self { 610 InputRedirection::AsRedirection(Redirection::File(f)) 611 } 612 } 613 614 /// Marker value for [`stdin`], [`stdout`], and [`stderr`] methods 615 /// of [`Exec`] and [`Pipeline`]. 616 /// 617 /// Use of this value means that the corresponding stream should 618 /// be redirected to the devnull device. 619 /// 620 /// [`stdin`]: struct.Exec.html#method.stdin 621 /// [`stdout`]: struct.Exec.html#method.stdout 622 /// [`stderr`]: struct.Exec.html#method.stderr 623 /// [`Exec`]: struct.Exec.html 624 /// [`Pipeline`]: struct.Pipeline.html 625 #[derive(Debug)] 626 pub struct NullFile; 627 628 impl From<NullFile> for InputRedirection { from(_nf: NullFile) -> Self629 fn from(_nf: NullFile) -> Self { 630 let null_file = OpenOptions::new().read(true).open(NULL_DEVICE).unwrap(); 631 InputRedirection::AsRedirection(Redirection::File(null_file)) 632 } 633 } 634 635 impl From<Vec<u8>> for InputRedirection { from(v: Vec<u8>) -> Self636 fn from(v: Vec<u8>) -> Self { 637 InputRedirection::FeedData(v) 638 } 639 } 640 641 impl<'a> From<&'a str> for InputRedirection { from(s: &'a str) -> Self642 fn from(s: &'a str) -> Self { 643 InputRedirection::FeedData(s.as_bytes().to_vec()) 644 } 645 } 646 647 #[derive(Debug)] 648 pub struct OutputRedirection(Redirection); 649 650 impl OutputRedirection { into_redirection(self) -> Redirection651 pub fn into_redirection(self) -> Redirection { 652 self.0 653 } 654 } 655 656 impl From<Redirection> for OutputRedirection { from(r: Redirection) -> Self657 fn from(r: Redirection) -> Self { 658 OutputRedirection(r) 659 } 660 } 661 662 impl From<File> for OutputRedirection { from(f: File) -> Self663 fn from(f: File) -> Self { 664 OutputRedirection(Redirection::File(f)) 665 } 666 } 667 668 impl From<NullFile> for OutputRedirection { from(_nf: NullFile) -> Self669 fn from(_nf: NullFile) -> Self { 670 let null_file = OpenOptions::new().write(true).open(NULL_DEVICE).unwrap(); 671 OutputRedirection(Redirection::File(null_file)) 672 } 673 } 674 675 #[cfg(unix)] 676 pub mod unix { 677 use super::Exec; 678 679 pub trait ExecExt { setuid(self, uid: u32) -> Self680 fn setuid(self, uid: u32) -> Self; setgid(self, gid: u32) -> Self681 fn setgid(self, gid: u32) -> Self; 682 } 683 684 impl ExecExt for Exec { setuid(mut self, uid: u32) -> Exec685 fn setuid(mut self, uid: u32) -> Exec { 686 self.config.setuid = Some(uid); 687 self 688 } 689 setgid(mut self, gid: u32) -> Exec690 fn setgid(mut self, gid: u32) -> Exec { 691 self.config.setgid = Some(gid); 692 self 693 } 694 } 695 } 696 } 697 698 mod pipeline { 699 use std::fmt; 700 use std::fs::File; 701 use std::io::{self, Read, Write}; 702 use std::ops::BitOr; 703 use std::rc::Rc; 704 705 use crate::communicate::{self, Communicator}; 706 use crate::os_common::ExitStatus; 707 use crate::popen::{Popen, Redirection, Result as PopenResult}; 708 709 use super::exec::{CaptureData, Exec, InputRedirection, OutputRedirection}; 710 711 /// A builder for multiple [`Popen`] instances connected via 712 /// pipes. 713 /// 714 /// A pipeline is a sequence of two or more [`Exec`] commands 715 /// connected via pipes. Just like in a Unix shell pipeline, each 716 /// command receives standard input from the previous command, and 717 /// passes standard output to the next command. Optionally, the 718 /// standard input of the first command can be provided from the 719 /// outside, and the output of the last command can be captured. 720 /// 721 /// In most cases you do not need to create [`Pipeline`] instances 722 /// directly; instead, combine [`Exec`] instances using the `|` 723 /// operator which produces `Pipeline`. 724 /// 725 /// # Examples 726 /// 727 /// Execute a pipeline and return the exit status of the last command: 728 /// 729 /// ```no_run 730 /// # use subprocess::*; 731 /// # fn dummy() -> Result<()> { 732 /// let exit_status = 733 /// (Exec::shell("ls *.bak") | Exec::cmd("xargs").arg("rm")).join()?; 734 /// # Ok(()) 735 /// # } 736 /// ``` 737 /// 738 /// Capture the pipeline's output: 739 /// 740 /// ```no_run 741 /// # use subprocess::*; 742 /// # fn dummy() -> Result<()> { 743 /// let dir_checksum = { 744 /// Exec::cmd("find . -type f") | Exec::cmd("sort") | Exec::cmd("sha1sum") 745 /// }.capture()?.stdout_str(); 746 /// # Ok(()) 747 /// # } 748 /// ``` 749 /// 750 /// [`Popen`]: struct.Popen.html 751 /// [`Exec`]: struct.Exec.html 752 /// [`Pipeline`]: struct.Pipeline.html 753 754 #[must_use] 755 pub struct Pipeline { 756 cmds: Vec<Exec>, 757 stdin: Redirection, 758 stdout: Redirection, 759 stderr_file: Option<File>, 760 stdin_data: Option<Vec<u8>>, 761 } 762 763 impl Pipeline { 764 /// Creates a new pipeline by combining two commands. 765 /// 766 /// Equivalent to `cmd1 | cmd2`. new(cmd1: Exec, cmd2: Exec) -> Pipeline767 pub fn new(cmd1: Exec, cmd2: Exec) -> Pipeline { 768 Pipeline { 769 cmds: vec![cmd1, cmd2], 770 stdin: Redirection::None, 771 stdout: Redirection::None, 772 stderr_file: None, 773 stdin_data: None, 774 } 775 } 776 777 /// Specifies how to set up the standard input of the first 778 /// command in the pipeline. 779 /// 780 /// Argument can be: 781 /// 782 /// * a [`Redirection`]; 783 /// * a `File`, which is a shorthand for `Redirection::File(file)`; 784 /// * a `Vec<u8>` or `&str`, which will set up a `Redirection::Pipe` 785 /// for stdin, making sure that `capture` feeds that data into the 786 /// standard input of the subprocess. 787 /// * `NullFile`, which will redirect the standard input to read from 788 /// /dev/null. 789 /// 790 /// [`Redirection`]: enum.Redirection.html stdin(mut self, stdin: impl Into<InputRedirection>) -> Pipeline791 pub fn stdin(mut self, stdin: impl Into<InputRedirection>) -> Pipeline { 792 match stdin.into() { 793 InputRedirection::AsRedirection(r) => self.stdin = r, 794 InputRedirection::FeedData(data) => { 795 self.stdin = Redirection::Pipe; 796 self.stdin_data = Some(data); 797 } 798 }; 799 self 800 } 801 802 /// Specifies how to set up the standard output of the last 803 /// command in the pipeline. 804 /// 805 /// Argument can be: 806 /// 807 /// * a [`Redirection`]; 808 /// * a `File`, which is a shorthand for `Redirection::File(file)`; 809 /// * `NullFile`, which will redirect the standard output to write to 810 /// /dev/null. 811 /// 812 /// [`Redirection`]: enum.Redirection.html stdout(mut self, stdout: impl Into<OutputRedirection>) -> Pipeline813 pub fn stdout(mut self, stdout: impl Into<OutputRedirection>) -> Pipeline { 814 self.stdout = stdout.into().into_redirection(); 815 self 816 } 817 818 /// Specifies a file to which to redirect the standard error of all 819 /// the commands in the pipeline. 820 /// 821 /// It is useful for capturing the standard error of the pipeline as a 822 /// whole. Unlike `stdout()`, which only affects the last command in 823 /// the pipeline, this affects all commands. The difference is 824 /// because standard output is piped from one command to the next, so 825 /// only the output of the last command is "free". In contrast, the 826 /// standard errors are not connected in any way. This is also the 827 /// reason only a `File` is supported - it allows for efficient 828 /// sharing of the same file by all commands. stderr_to(mut self, to: File) -> Pipeline829 pub fn stderr_to(mut self, to: File) -> Pipeline { 830 self.stderr_file = Some(to); 831 self 832 } 833 check_no_stdin_data(&self, meth: &str)834 fn check_no_stdin_data(&self, meth: &str) { 835 if self.stdin_data.is_some() { 836 panic!("{} called with input data specified", meth); 837 } 838 } 839 840 // Terminators: 841 842 /// Starts all commands in the pipeline, and returns a 843 /// `Vec<Popen>` whose members correspond to running commands. 844 /// 845 /// If some command fails to start, the remaining commands 846 /// will not be started, and the appropriate error will be 847 /// returned. The commands that have already started will be 848 /// waited to finish (but will probably exit immediately due 849 /// to missing output), except for the ones for which 850 /// `detached()` was called. This is equivalent to what the 851 /// shell does. popen(mut self) -> PopenResult<Vec<Popen>>852 pub fn popen(mut self) -> PopenResult<Vec<Popen>> { 853 self.check_no_stdin_data("popen"); 854 assert!(self.cmds.len() >= 2); 855 856 if let Some(stderr_to) = self.stderr_file { 857 let stderr_to = Rc::new(stderr_to); 858 self.cmds = self 859 .cmds 860 .into_iter() 861 .map(|cmd| cmd.stderr(Redirection::RcFile(Rc::clone(&stderr_to)))) 862 .collect(); 863 } 864 865 let first_cmd = self.cmds.drain(..1).next().unwrap(); 866 self.cmds.insert(0, first_cmd.stdin(self.stdin)); 867 868 let last_cmd = self.cmds.drain(self.cmds.len() - 1..).next().unwrap(); 869 self.cmds.push(last_cmd.stdout(self.stdout)); 870 871 let mut ret = Vec::<Popen>::new(); 872 let cnt = self.cmds.len(); 873 874 for (idx, mut runner) in self.cmds.into_iter().enumerate() { 875 if idx != 0 { 876 let prev_stdout = ret[idx - 1].stdout.take().unwrap(); 877 runner = runner.stdin(prev_stdout); 878 } 879 if idx != cnt - 1 { 880 runner = runner.stdout(Redirection::Pipe); 881 } 882 ret.push(runner.popen()?); 883 } 884 Ok(ret) 885 } 886 887 /// Starts the pipeline, waits for it to finish, and returns 888 /// the exit status of the last command. join(self) -> PopenResult<ExitStatus>889 pub fn join(self) -> PopenResult<ExitStatus> { 890 self.check_no_stdin_data("join"); 891 let mut v = self.popen()?; 892 // Waiting on a pipeline waits for all commands, but 893 // returns the status of the last one. This is how the 894 // shells do it. If the caller needs more precise control 895 // over which status is returned, they can call popen(). 896 v.last_mut().unwrap().wait() 897 } 898 899 /// Starts the pipeline and returns a value implementing the `Read` 900 /// trait that reads from the standard output of the last command. 901 /// 902 /// This will automatically set up 903 /// `stdout(Redirection::Pipe)`, so it is not necessary to do 904 /// that beforehand. 905 /// 906 /// When the trait object is dropped, it will wait for the 907 /// pipeline to finish. If this is undesirable, use 908 /// `detached()`. stream_stdout(self) -> PopenResult<impl Read>909 pub fn stream_stdout(self) -> PopenResult<impl Read> { 910 self.check_no_stdin_data("stream_stdout"); 911 let v = self.stdout(Redirection::Pipe).popen()?; 912 Ok(ReadPipelineAdapter(v)) 913 } 914 915 /// Starts the pipeline and returns a value implementing the `Write` 916 /// trait that writes to the standard input of the last command. 917 /// 918 /// This will automatically set up `stdin(Redirection::Pipe)`, 919 /// so it is not necessary to do that beforehand. 920 /// 921 /// When the trait object is dropped, it will wait for the 922 /// process to finish. If this is undesirable, use 923 /// `detached()`. stream_stdin(self) -> PopenResult<impl Write>924 pub fn stream_stdin(self) -> PopenResult<impl Write> { 925 self.check_no_stdin_data("stream_stdin"); 926 let v = self.stdin(Redirection::Pipe).popen()?; 927 Ok(WritePipelineAdapter(v)) 928 } 929 setup_communicate(mut self) -> PopenResult<(Communicator, Vec<Popen>)>930 fn setup_communicate(mut self) -> PopenResult<(Communicator, Vec<Popen>)> { 931 assert!(self.cmds.len() >= 2); 932 933 let (err_read, err_write) = crate::popen::make_pipe()?; 934 self = self.stderr_to(err_write); 935 936 let stdin_data = self.stdin_data.take(); 937 let mut v = self.stdout(Redirection::Pipe).popen()?; 938 let vlen = v.len(); 939 940 let comm = communicate::communicate( 941 v[0].stdin.take(), 942 v[vlen - 1].stdout.take(), 943 Some(err_read), 944 stdin_data, 945 ); 946 Ok((comm, v)) 947 } 948 949 /// Starts the pipeline and returns a `Communicator` handle. 950 /// 951 /// This is a lower-level API that offers more choice in how 952 /// communication is performed, such as read size limit and timeout, 953 /// equivalent to [`Popen::communicate`]. 954 /// 955 /// Unlike `capture()`, this method doesn't wait for the pipeline to 956 /// finish, effectively detaching it. 957 /// 958 /// [`Popen::communicate`]: struct.Popen.html#method.communicate communicate(mut self) -> PopenResult<Communicator>959 pub fn communicate(mut self) -> PopenResult<Communicator> { 960 self.cmds = self.cmds.into_iter().map(|cmd| cmd.detached()).collect(); 961 let comm = self.setup_communicate()?.0; 962 Ok(comm) 963 } 964 965 /// Starts the pipeline, collects its output, and waits for all 966 /// commands to finish. 967 /// 968 /// The return value provides the standard output of the last command, 969 /// the combined standard error of all commands, and the exit status 970 /// of the last command. The captured outputs can be accessed as 971 /// bytes or strings. 972 /// 973 /// Unlike `Popen::communicate`, this method actually waits for the 974 /// processes to finish, rather than simply waiting for the output to 975 /// close. If this is undesirable, use `detached()`. capture(self) -> PopenResult<CaptureData>976 pub fn capture(self) -> PopenResult<CaptureData> { 977 let (mut comm, mut v) = self.setup_communicate()?; 978 let (out, err) = comm.read()?; 979 let out = out.unwrap_or_else(Vec::new); 980 let err = err.unwrap(); 981 982 let vlen = v.len(); 983 let status = v[vlen - 1].wait()?; 984 985 Ok(CaptureData { 986 stdout: out, 987 stderr: err, 988 exit_status: status, 989 }) 990 } 991 } 992 993 impl Clone for Pipeline { 994 /// Returns a copy of the value. 995 /// 996 /// This method is guaranteed not to fail as long as none of 997 /// the `Redirection` values contain a `Redirection::File` 998 /// variant. If a redirection to `File` is present, cloning 999 /// that field will use `File::try_clone` method, which 1000 /// duplicates a file descriptor and can (but is not likely 1001 /// to) fail. In that scenario, `Exec::clone` panics. clone(&self) -> Pipeline1002 fn clone(&self) -> Pipeline { 1003 Pipeline { 1004 cmds: self.cmds.clone(), 1005 stdin: self.stdin.try_clone().unwrap(), 1006 stdout: self.stdout.try_clone().unwrap(), 1007 stderr_file: self.stderr_file.as_ref().map(|f| f.try_clone().unwrap()), 1008 stdin_data: self.stdin_data.clone(), 1009 } 1010 } 1011 } 1012 1013 impl BitOr<Exec> for Pipeline { 1014 type Output = Pipeline; 1015 1016 /// Append a command to the pipeline and return a new pipeline. bitor(mut self, rhs: Exec) -> Pipeline1017 fn bitor(mut self, rhs: Exec) -> Pipeline { 1018 self.cmds.push(rhs); 1019 self 1020 } 1021 } 1022 1023 impl BitOr for Pipeline { 1024 type Output = Pipeline; 1025 1026 /// Append a pipeline to the pipeline and return a new pipeline. bitor(mut self, rhs: Pipeline) -> Pipeline1027 fn bitor(mut self, rhs: Pipeline) -> Pipeline { 1028 self.cmds.extend(rhs.cmds); 1029 self.stdout = rhs.stdout; 1030 self 1031 } 1032 } 1033 1034 impl fmt::Debug for Pipeline { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1035 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1036 let mut args = vec![]; 1037 for cmd in &self.cmds { 1038 args.push(cmd.to_cmdline_lossy()); 1039 } 1040 write!(f, "Pipeline {{ {} }}", args.join(" | ")) 1041 } 1042 } 1043 1044 #[derive(Debug)] 1045 struct ReadPipelineAdapter(Vec<Popen>); 1046 1047 impl Read for ReadPipelineAdapter { read(&mut self, buf: &mut [u8]) -> io::Result<usize>1048 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { 1049 let last = self.0.last_mut().unwrap(); 1050 last.stdout.as_mut().unwrap().read(buf) 1051 } 1052 } 1053 1054 #[derive(Debug)] 1055 struct WritePipelineAdapter(Vec<Popen>); 1056 1057 impl WritePipelineAdapter { stdin(&mut self) -> &mut File1058 fn stdin(&mut self) -> &mut File { 1059 let first = self.0.first_mut().unwrap(); 1060 first.stdin.as_mut().unwrap() 1061 } 1062 } 1063 1064 impl Write for WritePipelineAdapter { write(&mut self, buf: &[u8]) -> io::Result<usize>1065 fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 1066 self.stdin().write(buf) 1067 } flush(&mut self) -> io::Result<()>1068 fn flush(&mut self) -> io::Result<()> { 1069 self.stdin().flush() 1070 } 1071 } 1072 1073 impl Drop for WritePipelineAdapter { 1074 // the same rationale as Drop for WriteAdapter drop(&mut self)1075 fn drop(&mut self) { 1076 let first = &mut self.0[0]; 1077 first.stdin.take(); 1078 } 1079 } 1080 } 1081