| 
						
						
							
								
							
						
						
					 | 
					 | 
					@ -11,6 +11,9 @@ use std::os::fd::{BorrowedFd, FromRawFd};
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					use std::os::unix::io::AsRawFd;
 | 
					 | 
					 | 
					 | 
					use std::os::unix::io::AsRawFd;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					use std::ptr;
 | 
					 | 
					 | 
					 | 
					use std::ptr;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					static mut USE_KERNEL_ORDERING: bool = false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					static mut PLAIN_MODE: bool = false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					#[derive(Debug, Default)]
 | 
					 | 
					 | 
					 | 
					#[derive(Debug, Default)]
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					struct Ptys {
 | 
					 | 
					 | 
					 | 
					struct Ptys {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    out_slave: libc::c_int,
 | 
					 | 
					 | 
					 | 
					    out_slave: libc::c_int,
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -39,20 +42,31 @@ fn handle_data(mut stream: StdioStream) -> Result<(), bool> {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        Ok(0) => Err(false), // EOF
 | 
					 | 
					 | 
					 | 
					        Ok(0) => Err(false), // EOF
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        Ok(n) => {
 | 
					 | 
					 | 
					 | 
					        Ok(n) => {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            let bufc = &buf[..n];
 | 
					 | 
					 | 
					 | 
					            let bufc = &buf[..n];
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            for c in bufc {
 | 
					 | 
					 | 
					 | 
					            if unsafe {PLAIN_MODE} {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                stream.buffer.push(*c);
 | 
					 | 
					 | 
					 | 
					                std::io::stdout().write_all(bufc).unwrap();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                if *c == 0x0a as u8 {
 | 
					 | 
					 | 
					 | 
					            } else {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                    let format = String::from("%H:%M:%S.%6f")
 | 
					 | 
					 | 
					 | 
					                for c in bufc {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                        + match (stream.is_tty, stream.var) {
 | 
					 | 
					 | 
					 | 
					                    stream.buffer.push(*c);
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                            (true, StdioStreamType::StdOut) => " \x1b[32m(O)\x1b[0m ",
 | 
					 | 
					 | 
					 | 
					                    if *c == 0x0a as u8 {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                            (false, StdioStreamType::StdOut) => " (O) ",
 | 
					 | 
					 | 
					 | 
					                        let format = String::from("%H:%M:%S.%6f")
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                            (true, StdioStreamType::StdErr) => " \x1b[31m(E)\x1b[0m ",
 | 
					 | 
					 | 
					 | 
					                            + if unsafe{USE_KERNEL_ORDERING} {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                            (false, StdioStreamType::StdErr) => " (E) ",
 | 
					 | 
					 | 
					 | 
					                                match stream.is_tty {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                        };
 | 
					 | 
					 | 
					 | 
					                                    true => " \x1b[34m(?)\x1b[0m ",
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                    let now = Local::now().format(&format).to_string();
 | 
					 | 
					 | 
					 | 
					                                    false => " (?) ",
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                    std::io::stdout().write_all(now.as_bytes()).unwrap();
 | 
					 | 
					 | 
					 | 
					                                }
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                    std::io::stdout().write_all(&stream.buffer).unwrap();
 | 
					 | 
					 | 
					 | 
					                            } else {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                    stream.buffer.clear();
 | 
					 | 
					 | 
					 | 
					                                match (stream.is_tty, stream.var) {
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                                    (true, StdioStreamType::StdOut) => " \x1b[32m(O)\x1b[0m ",
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                                    (false, StdioStreamType::StdOut) => " (O) ",
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                                    (true, StdioStreamType::StdErr) => " \x1b[31m(E)\x1b[0m ",
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                                    (false, StdioStreamType::StdErr) => " (E) ",
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                                }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                            };
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                        let now = Local::now().format(&format).to_string();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                        std::io::stdout().write_all(now.as_bytes()).unwrap();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                        std::io::stdout().write_all(&stream.buffer).unwrap();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                        stream.buffer.clear();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                }
 | 
					 | 
					 | 
					 | 
					                }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            }
 | 
					 | 
					 | 
					 | 
					            }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            std::io::stdout().flush().unwrap();
 | 
					 | 
					 | 
					 | 
					            std::io::stdout().flush().unwrap();
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -89,13 +103,14 @@ fn open_ptys(ptys: &mut Ptys) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    assert!(ptys.err_master != 0);
 | 
					 | 
					 | 
					 | 
					    assert!(ptys.err_master != 0);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					static mut IS_TTY: bool = false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fn handle_poll(
 | 
					 | 
					 | 
					 | 
					fn handle_poll(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    poll_fd: &PollFd<'_>,
 | 
					 | 
					 | 
					 | 
					    poll_fd: &PollFd<'_>,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    var: StdioStreamType,
 | 
					 | 
					 | 
					 | 
					    var: StdioStreamType,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    master_file: &File,
 | 
					 | 
					 | 
					 | 
					    master_file: &File,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    mut buf: &mut Vec<u8>,
 | 
					 | 
					 | 
					 | 
					    mut buf: &mut Vec<u8>,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					) -> Result<(), bool> {
 | 
					 | 
					 | 
					 | 
					) -> Result<(), bool> {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    let is_tty = unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 };
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    let revents = poll_fd.revents();
 | 
					 | 
					 | 
					 | 
					    let revents = poll_fd.revents();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    if let Some(revents) = revents {
 | 
					 | 
					 | 
					 | 
					    if let Some(revents) = revents {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if revents.contains(PollFlags::POLLHUP) {
 | 
					 | 
					 | 
					 | 
					        if revents.contains(PollFlags::POLLHUP) {
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -105,25 +120,32 @@ fn handle_poll(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            return handle_data(StdioStream {
 | 
					 | 
					 | 
					 | 
					            return handle_data(StdioStream {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                var: var,
 | 
					 | 
					 | 
					 | 
					                var: var,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                file: &master_file,
 | 
					 | 
					 | 
					 | 
					                file: &master_file,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                is_tty: is_tty,
 | 
					 | 
					 | 
					 | 
					                is_tty: unsafe { IS_TTY },
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                buffer: &mut buf,
 | 
					 | 
					 | 
					 | 
					                buffer: &mut buf,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            });
 | 
					 | 
					 | 
					 | 
					            });
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        }
 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        Err(false)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    } else {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        Err(false)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    }
 | 
					 | 
					 | 
					 | 
					    }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    Ok(())
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fn spawn_child(ptys: &Ptys) {
 | 
					 | 
					 | 
					 | 
					fn spawn_child(ptys: &Ptys, user_cmd: String) {
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    let cmd = CString::new("/bin/bash").unwrap();
 | 
					 | 
					 | 
					 | 
					    let cmd = CString::new("/bin/bash").unwrap();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    let bcmd = std::env::args().skip(1).collect::<Vec<String>>().join(" ");
 | 
					 | 
					 | 
					 | 
					    let bcmd = user_cmd;
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    println!("Cmd: '{}'", bcmd);
 | 
					 | 
					 | 
					 | 
					    if !unsafe {PLAIN_MODE} {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					        println!("Cmd: '{}'", bcmd);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    setsid().expect("Failed to create new session");
 | 
					 | 
					 | 
					 | 
					    setsid().expect("Failed to create new session");
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    unsafe { libc::close(ptys.out_master.as_raw_fd()) };
 | 
					 | 
					 | 
					 | 
					    unsafe { libc::close(ptys.out_master.as_raw_fd()) };
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    unsafe {
 | 
					 | 
					 | 
					 | 
					    unsafe {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        libc::dup2(ptys.out_slave.as_raw_fd(), libc::STDOUT_FILENO);
 | 
					 | 
					 | 
					 | 
					        libc::dup2(ptys.out_slave.as_raw_fd(), libc::STDOUT_FILENO);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        libc::dup2(ptys.err_slave.as_raw_fd(), libc::STDERR_FILENO);
 | 
					 | 
					 | 
					 | 
					        if USE_KERNEL_ORDERING {
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            libc::dup2(ptys.out_slave.as_raw_fd(), libc::STDERR_FILENO);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        } else {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            libc::dup2(ptys.err_slave.as_raw_fd(), libc::STDERR_FILENO);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // There's no real reason to dup the stdin.
 | 
					 | 
					 | 
					 | 
					        // There's no real reason to dup the stdin.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // It's not being used anyway.
 | 
					 | 
					 | 
					 | 
					        // It's not being used anyway.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // ----------------------------------------------------------
 | 
					 | 
					 | 
					 | 
					        // ----------------------------------------------------------
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -173,8 +195,11 @@ fn main_loop(child: Pid, ptys: &Ptys) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        ),
 | 
					 | 
					 | 
					 | 
					        ),
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    ];
 | 
					 | 
					 | 
					 | 
					    ];
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    let mut out_buf: Vec<u8> = Vec::new();
 | 
					 | 
					 | 
					 | 
					    let mut out_buf: Vec<u8> = Vec::with_capacity(65536);
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    let mut err_buf: Vec<u8> = Vec::new();
 | 
					 | 
					 | 
					 | 
					    let mut err_buf: Vec<u8> = Vec::with_capacity(65536);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    let mut writing_out = false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    let mut writing_err = false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    loop {
 | 
					 | 
					 | 
					 | 
					    loop {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        let res = poll(&mut poll_fds, PollTimeout::ZERO);
 | 
					 | 
					 | 
					 | 
					        let res = poll(&mut poll_fds, PollTimeout::ZERO);
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -183,52 +208,143 @@ fn main_loop(child: Pid, ptys: &Ptys) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            std::process::exit(-1);
 | 
					 | 
					 | 
					 | 
					            std::process::exit(-1);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        }
 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        match handle_poll(
 | 
					 | 
					 | 
					 | 
					        assert!(res != Ok(2), "Race condition between stdio and stderr");
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            &poll_fds[1],
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            StdioStreamType::StdErr,
 | 
					 | 
					 | 
					 | 
					        if unsafe{USE_KERNEL_ORDERING} {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            &master_file_err,
 | 
					 | 
					 | 
					 | 
					            match handle_poll(
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            &mut err_buf,
 | 
					 | 
					 | 
					 | 
					                &poll_fds[0],
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        ) {
 | 
					 | 
					 | 
					 | 
					                StdioStreamType::StdOut,
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            Ok(_) => {}
 | 
					 | 
					 | 
					 | 
					                &master_file_out,
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            Err(true) => break,
 | 
					 | 
					 | 
					 | 
					                &mut out_buf,
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            Err(false) => continue,
 | 
					 | 
					 | 
					 | 
					            ) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        }
 | 
					 | 
					 | 
					 | 
					                Ok(_) => {}
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        match handle_poll(
 | 
					 | 
					 | 
					 | 
					                Err(true) => break,
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            &poll_fds[0],
 | 
					 | 
					 | 
					 | 
					                Err(false) => {}
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            StdioStreamType::StdOut,
 | 
					 | 
					 | 
					 | 
					            }
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            &master_file_out,
 | 
					 | 
					 | 
					 | 
					        } else {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            &mut out_buf,
 | 
					 | 
					 | 
					 | 
					            if !writing_out {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        ) {
 | 
					 | 
					 | 
					 | 
					                match handle_poll(
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            Ok(_) => {}
 | 
					 | 
					 | 
					 | 
					                    &poll_fds[1],
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            Err(true) => break,
 | 
					 | 
					 | 
					 | 
					                    StdioStreamType::StdErr,
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            Err(false) => continue,
 | 
					 | 
					 | 
					 | 
					                    &master_file_err,
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    &mut err_buf,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                ) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    Ok(_) => {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                        writing_err = true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                        writing_out = false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    Err(true) => break,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    Err(false) => {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                        writing_err = false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                        writing_out = true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            if !writing_err {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                match handle_poll(
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    &poll_fds[0],
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    StdioStreamType::StdOut,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    &master_file_out,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    &mut out_buf,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                ) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    Ok(_) => {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                        writing_err = false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                        writing_out = true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    Err(true) => break,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    Err(false) => {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                        writing_err = true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                        writing_out = false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                    }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        }
 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if res.ok().unwrap() == 0 && unsafe { kill(child.as_raw(), 0) } != 0 {
 | 
					 | 
					 | 
					 | 
					        if res.ok().unwrap() == 0 {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // The poll might've timed out and in the short time between
 | 
					 | 
					 | 
					 | 
					            writing_out = false;
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // the poll timeout and the check if the process is alive,
 | 
					 | 
					 | 
					 | 
					            writing_err = false;
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // there might be pending data (unless the kernel deletes it...)
 | 
					 | 
					 | 
					 | 
					            if unsafe { kill(child.as_raw(), 0) } != 0 {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // I have no evidence supporting this theory, though.
 | 
					 | 
					 | 
					 | 
					                // The poll might've timed out and in the short time between
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // -------------------------------------------------------------
 | 
					 | 
					 | 
					 | 
					                // the poll timeout and the check if the process is alive,
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // let mut buf = [0u8; 64];
 | 
					 | 
					 | 
					 | 
					                // there might be pending data (unless the kernel deletes it...)
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // match master_file.read(&mut buf) {
 | 
					 | 
					 | 
					 | 
					                // I have no evidence supporting this theory, though.
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            //     Ok(e) => println!("Ok: {}", e),
 | 
					 | 
					 | 
					 | 
					                // -------------------------------------------------------------
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            //     Err(_e) => {/*println!("Err: {}", e)*/}
 | 
					 | 
					 | 
					 | 
					                // let mut buf = [0u8; 64];
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // }
 | 
					 | 
					 | 
					 | 
					                // match master_file.read(&mut buf) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            break;
 | 
					 | 
					 | 
					 | 
					                //     Ok(e) => println!("Ok: {}", e),
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                //     Err(_e) => {/*println!("Err: {}", e)*/}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                // }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        }
 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        waitpid(child, Some(WaitPidFlag::WNOHANG)).ok();
 | 
					 | 
					 | 
					 | 
					        waitpid(child, Some(WaitPidFlag::WNOHANG)).ok();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    }
 | 
					 | 
					 | 
					 | 
					    }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					use std::ffi::OsString;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					#[derive(Debug)]
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					struct Args {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    kernel_order: bool,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    plain: bool,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    command: String,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					fn parse_args() -> Args {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    let osargs = std::env::args_os();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    let args = osargs.collect::<Vec<OsString>>();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    let mut args = args.into_iter().skip(1); // skip program name
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    let mut kernel_order = false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    let mut plain = false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    let mut command_parts: Vec<OsString> = Vec::new();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    while let Some(arg) = args.next() {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        if arg == "--kernel-order" {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            kernel_order = true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        } else if arg == "--plain" {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            plain = true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        } else if arg == "-c" || arg == "--command" {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            command_parts.extend(args);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        } else {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            command_parts.push(arg);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            command_parts.extend(args);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            break;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    let command = command_parts
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        .into_iter()
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        .map(|s| s.to_string_lossy().into_owned())
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        .collect::<Vec<_>>()
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        .join(" ");
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    let parsed = Args {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        kernel_order,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        command,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        plain,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    };
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    parsed
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					fn main() {
 | 
					 | 
					 | 
					 | 
					fn main() {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    let args = parse_args();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    let cmd = args.command;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    unsafe { 
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        IS_TTY = libc::isatty(libc::STDOUT_FILENO) != 0;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        USE_KERNEL_ORDERING = args.kernel_order;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        PLAIN_MODE = args.plain;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    };
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    let mut ptys = Ptys::default();
 | 
					 | 
					 | 
					 | 
					    let mut ptys = Ptys::default();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    open_ptys(&mut ptys);
 | 
					 | 
					 | 
					 | 
					    open_ptys(&mut ptys);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    match unsafe { fork() } {
 | 
					 | 
					 | 
					 | 
					    match unsafe { fork() } {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        Ok(ForkResult::Child) => {
 | 
					 | 
					 | 
					 | 
					        Ok(ForkResult::Child) => {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            spawn_child(&ptys);
 | 
					 | 
					 | 
					 | 
					            spawn_child(&ptys, cmd);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        }
 | 
					 | 
					 | 
					 | 
					        }
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        Ok(ForkResult::Parent { child }) => {
 | 
					 | 
					 | 
					 | 
					        Ok(ForkResult::Parent { child }) => {
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					 | 
					
 
 |