From a2e5875d37a9c8cb5a988c6a48d7b10f6c6a1c89 Mon Sep 17 00:00:00 2001
From: Michael Aaron Murphy <mmstickman@gmail.com>
Date: Fri, 14 Jul 2017 19:31:23 -0400
Subject: [PATCH] Convert `children: Vec<Option<Child>>` To Vec<u32>

---
 src/shell/pipe.rs | 46 +++++++++++++++++++++-------------------------
 1 file changed, 21 insertions(+), 25 deletions(-)

diff --git a/src/shell/pipe.rs b/src/shell/pipe.rs
index 09c1d769..0b58d840 100644
--- a/src/shell/pipe.rs
+++ b/src/shell/pipe.rs
@@ -1,7 +1,7 @@
 #[cfg(all(unix, not(target_os = "redox")))] use libc;
 #[cfg(target_os = "redox")] use syscall;
 use std::io::{self, Write};
-use std::process::{Stdio, Command, Child};
+use std::process::{Stdio, Command};
 use std::os::unix::io::{FromRawFd, IntoRawFd};
 use std::os::unix::process::CommandExt;
 use std::fs::{File, OpenOptions};
@@ -287,7 +287,8 @@ pub fn pipe (
                     // owned by a given command in `wait` in order to close those pipes, sending
                     // EOF to the next command
                     let mut remember = Vec::new();
-                    let mut children: Vec<Option<Child>> = Vec::new();
+                    // A list of the PIDs in the piped command
+                    let mut children: Vec<u32> = Vec::new();
 
                     macro_rules! spawn_proc {
                         ($cmd:expr) => {{
@@ -299,15 +300,11 @@ pub fn pipe (
                             match child {
                                 Ok(child) => {
                                     shell.foreground.push(child.id());
-                                    children.push(Some(child))
+                                    children.push(child.id());
                                 },
                                 Err(e) => {
-                                    children.push(None);
-                                    eprintln! (
-                                        "ion: failed to spawn `{}`: {}",
-                                        get_command_name($cmd),
-                                        e
-                                    );
+                                    eprintln!("ion: failed to spawn `{}`: {}", get_command_name($cmd), e);
+                                    return NO_SUCH_COMMAND
                                 }
                             }
                         }};
@@ -384,33 +381,32 @@ fn execute_command(shell: &mut Shell, command: &mut Command, foreground: bool) -
     }
 }
 
-/// This function will panic if called with an empty vector
+/// Waits for all of the children within a pipe to finish exuecting, returning the
+/// exit status of the last process in the queue. TODO: we need a way of
+/// enabling the last command in the pipe to close it's FDs so that the SIGPIPE
+/// signal is propagated back to the first command. Otherwise, there's an issue
+/// where a command like `yes | head` will wait forever, until Ctrl+C'd.
 fn wait (
     shell: &mut Shell,
-    children: &mut Vec<Option<Child>>,
+    children: &mut Vec<u32>,
     mut commands: Vec<Command>,
     foreground: bool
 ) -> i32 {
     let end = children.len() - 1;
-    for entry in children.drain(..end).zip(commands.drain(..end)) {
+    for (child, cmd) in children.drain(..end).zip(commands.drain(..end)) {
         // It is important that `cmd` gets dropped at the end of this
         // block in order to write EOF to the pipes that it owns.
-        if let (Some(child), cmd) = entry {
-            if foreground { set_foreground(child.id()); }
-            let status = shell.watch_foreground(child.id(), || get_full_command(&cmd));
-            if status == TERMINATED {
-                return status
-            }
+        if foreground { set_foreground(child); }
+        let status = shell.watch_foreground(child, || get_full_command(&cmd));
+        if status == TERMINATED {
+            return status
         }
     }
 
-    if let Some(child) = children.pop().unwrap() {
-        let cmd = commands.pop().unwrap();
-        if foreground { set_foreground(child.id()); }
-        shell.watch_foreground(child.id(), || get_full_command(&cmd))
-    } else {
-        NO_SUCH_COMMAND
-    }
+    let child = children.pop().unwrap();
+    let cmd = commands.pop().unwrap();
+    if foreground { set_foreground(child); }
+    shell.watch_foreground(child, || get_full_command(&cmd))
 }
 
 fn get_command_name(command: &Command) -> String {
-- 
GitLab