pub fn spawn<T>(mut cmd: Command, cmdline: &[T]) -> Result<ProcessTree>
        where T: AsRef<str>
    {
        let started = Local::now();
        let child = cmd.spawn_ptrace().chain_err(|| "Error spawning process")?;
        let pid = child.id() as pid_t;
        trace!("Spawned process {}", pid);
        // Setup our ptrace options
        ptrace_setoptions(pid, PTRACE_O_TRACEEXEC | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE).chain_err(|| "Error setting ptrace options")?;
        let mut arena = Arena::new();
        let mut pids = HashMap::new();
        let root = get_or_insert_pid(pid, &mut arena, &mut pids);
        arena[root].data.cmdline = cmdline.iter().map(|s| s.as_ref().to_string()).collect();
        arena[root].data.cwd = get_cwd(pid);
        continue_process(pid, None).chain_err(|| "Error continuing process")?;
        loop {
            if !root.descendants(&arena).any(|node| arena[node].data.ended.is_none()) {
                break
            }
            match waitpid(-1, None) {
                Ok(WaitStatus::Exited(pid, ret)) => {
                    trace!("Process {} exited with status {}", pid, ret);
                    let node = get_or_insert_pid(pid, &mut arena, &mut pids);
                    arena[node].data.ended = Some(Instant::now());
                }
                Ok(WaitStatus::Signaled(pid, sig, _)) => {
                    trace!("Process {} exited with signal {:?}", pid, sig);
                    let node = get_or_insert_pid(pid, &mut arena, &mut pids);
                    arena[node].data.ended = Some(Instant::now());
                }
                Ok(WaitStatus::PtraceEvent(pid, _sig, event)) => {
                    match event {
                        PTRACE_EVENT_FORK | PTRACE_EVENT_VFORK | PTRACE_EVENT_CLONE => {
                            let mut new_pid: pid_t = 0;
                            ptrace(PTRACE_GETEVENTMSG, pid, ptr::null_mut(),
                                   &mut new_pid as *mut pid_t as *mut c_void)
                                .chain_err(|| "Failed to get pid of forked process")?;
                            let name = match event {
                                PTRACE_EVENT_FORK => "fork",
                                PTRACE_EVENT_VFORK => "vfork",
                                PTRACE_EVENT_CLONE => "clone",
                                _ => unreachable!(),
                            };
                            trace!("[{}] {} new process {}", pid, name, new_pid);
                            match pids.get(&pid) {
                                Some(&parent) => {
                                    let cmdline = {
                                        let parent_data = &arena[parent].data;
                                        if parent_data.cmdline.len() > 1 {
                                            parent_data.cmdline[..1].to_vec()
                                        } else {
                                            vec![]
                                        }
                                    };
                                    let child = get_or_insert_pid(new_pid, &mut arena, &mut pids);
                                    arena[child].data.cmdline = cmdline;
                                    arena[child].data.cwd = get_cwd(new_pid);
                                    parent.append(child, &mut arena);
                                }
                                None => bail!("Got an {:?} event for unknown parent pid {}", event,
                                              pid),
                            }
                        }
                        PTRACE_EVENT_EXEC => {
                            let mut buf = vec!();
                            match pids.get(&pid) {
                                Some(&node) => {
                                    File::open(format!("/proc/{}/cmdline", pid))
                                        .and_then(|mut f| f.read_to_end(&mut buf))
                                        .and_then(|_| {
                                            let mut cmdline = buf.split(|&b| b == 0).map(|bytes| String::from_utf8_lossy(bytes).into_owned()).collect::<Vec<_>>();
                                            cmdline.pop();
                                            debug!("[{}] exec {:?}", pid, cmdline);
                                            arena[node].data.cmdline = cmdline;
                                            Ok(())
                                        })
                                        .chain_err(|| "Couldn't read cmdline")?;
                                }
                                None => bail!("Got an exec event for unknown pid {}", pid),
                            }
                        }
                        _ => panic!("Unexpected ptrace event: {:?}", event),
                    }
                    continue_process(pid, None).chain_err(|| "Error continuing process")?;
                }
                Ok(WaitStatus::Stopped(pid, sig)) => {
                    trace!("[{}] stopped with {:?}", pid, sig);
                    // Sometimes we get the SIGSTOP+exit from a child before we get the clone
                    // stop from the parent, so insert any unknown pids here so we have a better
                    // approximation of the process start time.
                    get_or_insert_pid(pid, &mut arena, &mut pids);
                    let continue_sig = if sig == signal::Signal::SIGSTOP { None } else { Some(sig) };
                    continue_process(pid, continue_sig).chain_err(|| "Error continuing process")?;
                }
                Ok(s) => bail!("Unexpected process status: {:?}", s),
                Err(e) => {
                    match e {
                        nix::Error::Sys(nix::Errno::EINTR) => {
                            /*FIXME
                            if SIGNAL_DELIVERED.swap(false, Ordering::Relaxed) {
                                println!("Active processes:");
                                print_process_tree(root, arena, |info| info.ended.is_none());
                            }
                             */
                        }
                        _ => bail!("ptrace error: {:?}", e),
                    }
                }
            }
        }
        Ok(ProcessTree {
            arena: arena,
            pids: pids,
            root: root,
            started: started,
        })
    }
/// Execute `cmd`, tracking all child processes it spawns, and return a `ProcessTree` listing
/// them.
Execute `cmd`, tracking all child processes it spawns, and return a `ProcessTree` listing
them.
Execute ` cmd ` tracking all child processes it spawns and return a ` ProcessTree ` listing them .
pub fn spawn<T>(mut cmd: Command, cmdline: &[T]) -> Result<ProcessTree>
        where T: AsRef<str>
    {
        let started = Local::now();
        let child = cmd.spawn_ptrace().chain_err(|| "Error spawning process")?;
        let pid = child.id() as pid_t;
        trace!("Spawned process {}", pid);
        // Setup our ptrace options
        ptrace_setoptions(pid, PTRACE_O_TRACEEXEC | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE).chain_err(|| "Error setting ptrace options")?;
        let mut arena = Arena::new();
        let mut pids = HashMap::new();
        let root = get_or_insert_pid(pid, &mut arena, &mut pids);
        arena[root].data.cmdline = cmdline.iter().map(|s| s.as_ref().to_string()).collect();
        arena[root].data.cwd = get_cwd(pid);
        continue_process(pid, None).chain_err(|| "Error continuing process")?;
        loop {
            if !root.descendants(&arena).any(|node| arena[node].data.ended.is_none()) {
                break
            }
            match waitpid(-1, None) {
                Ok(WaitStatus::Exited(pid, ret)) => {
                    trace!("Process {} exited with status {}", pid, ret);
                    let node = get_or_insert_pid(pid, &mut arena, &mut pids);
                    arena[node].data.ended = Some(Instant::now());
                }
                Ok(WaitStatus::Signaled(pid, sig, _)) => {
                    trace!("Process {} exited with signal {:?}", pid, sig);
                    let node = get_or_insert_pid(pid, &mut arena, &mut pids);
                    arena[node].data.ended = Some(Instant::now());
                }
                Ok(WaitStatus::PtraceEvent(pid, _sig, event)) => {
                    match event {
                        PTRACE_EVENT_FORK | PTRACE_EVENT_VFORK | PTRACE_EVENT_CLONE => {
                            let mut new_pid: pid_t = 0;
                            ptrace(PTRACE_GETEVENTMSG, pid, ptr::null_mut(),
                                   &mut new_pid as *mut pid_t as *mut c_void)
                                .chain_err(|| "Failed to get pid of forked process")?;
                            let name = match event {
                                PTRACE_EVENT_FORK => "fork",
                                PTRACE_EVENT_VFORK => "vfork",
                                PTRACE_EVENT_CLONE => "clone",
                                _ => unreachable!(),
                            };
                            trace!("[{}] {} new process {}", pid, name, new_pid);
                            match pids.get(&pid) {
                                Some(&parent) => {
                                    let cmdline = {
                                        let parent_data = &arena[parent].data;
                                        if parent_data.cmdline.len() > 1 {
                                            parent_data.cmdline[..1].to_vec()
                                        } else {
                                            vec![]
                                        }
                                    };
                                    let child = get_or_insert_pid(new_pid, &mut arena, &mut pids);
                                    arena[child].data.cmdline = cmdline;
                                    arena[child].data.cwd = get_cwd(new_pid);
                                    parent.append(child, &mut arena);
                                }
                                None => bail!("Got an {:?} event for unknown parent pid {}", event,
                                              pid),
                            }
                        }
                        PTRACE_EVENT_EXEC => {
                            let mut buf = vec!();
                            match pids.get(&pid) {
                                Some(&node) => {
                                    File::open(format!("/proc/{}/cmdline", pid))
                                        .and_then(|mut f| f.read_to_end(&mut buf))
                                        .and_then(|_| {
                                            let mut cmdline = buf.split(|&b| b == 0).map(|bytes| String::from_utf8_lossy(bytes).into_owned()).collect::<Vec<_>>();
                                            cmdline.pop();
                                            debug!("[{}] exec {:?}", pid, cmdline);
                                            arena[node].data.cmdline = cmdline;
                                            Ok(())
                                        })
                                        .chain_err(|| "Couldn't read cmdline")?;
                                }
                                None => bail!("Got an exec event for unknown pid {}", pid),
                            }
                        }
                        _ => panic!("Unexpected ptrace event: {:?}", event),
                    }
                    continue_process(pid, None).chain_err(|| "Error continuing process")?;
                }
                Ok(WaitStatus::Stopped(pid, sig)) => {
                    trace!("[{}] stopped with {:?}", pid, sig);
                    // Sometimes we get the SIGSTOP+exit from a child before we get the clone
                    // stop from the parent, so insert any unknown pids here so we have a better
                    // approximation of the process start time.
                    get_or_insert_pid(pid, &mut arena, &mut pids);
                    let continue_sig = if sig == signal::Signal::SIGSTOP { None } else { Some(sig) };
                    continue_process(pid, continue_sig).chain_err(|| "Error continuing process")?;
                }
                Ok(s) => bail!("Unexpected process status: {:?}", s),
                Err(e) => {
                    match e {
                        nix::Error::Sys(nix::Errno::EINTR) => {
                            /*FIXME
                            if SIGNAL_DELIVERED.swap(false, Ordering::Relaxed) {
                                println!("Active processes:");
                                print_process_tree(root, arena, |info| info.ended.is_none());
                            }
                             */
                        }
                        _ => bail!("ptrace error: {:?}", e),
                    }
                }
            }
        }
        Ok(ProcessTree {
            arena: arena,
            pids: pids,
            root: root,
            started: started,
        })
    }
pub fn spawn < T > ( mut cmd : Command , cmdline : & [ T ] ) -> Result < ProcessTree > where T : AsRef < str > { let started = Local :: now ( ) ; let child = cmd . spawn_ptrace ( ) . chain_err ( | | " " ) ? ; let pid = child . id ( ) as pid_t ; trace ! ( " " pid ) ; // Setup our ptrace options ptrace_setoptions ( pid , PTRACE_O_TRACEEXEC | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE ) . chain_err ( | | " " ) ? ; let mut arena = Arena :: new ( ) ; let mut pids = HashMap :: new ( ) ; let root = get_or_insert_pid ( pid , & mut arena , & mut pids ) ; arena [ root ] . data . cmdline = cmdline . iter ( ) . map ( | s | s . as_ref ( ) . to_string ( ) ) . collect ( ) ; arena [ root ] . data . cwd = get_cwd ( pid ) ; continue_process ( pid , None ) . chain_err ( | | " " ) ? ; loop { if ! root . descendants ( & arena ) . any ( | node | arena [ node ] . data . ended . is_none ( ) ) { break } match waitpid ( - 1 , None ) { Ok ( WaitStatus :: Exited ( pid , ret ) ) => { trace ! ( " " pid ret ) ; let node = get_or_insert_pid ( pid , & mut arena , & mut pids ) ; arena [ node ] . data . ended = Some ( Instant :: now ( ) ) ; } Ok ( WaitStatus :: Signaled ( pid , sig , _ ) ) => { trace ! ( " " pid sig ) ; let node = get_or_insert_pid ( pid , & mut arena , & mut pids ) ; arena [ node ] . data . ended = Some ( Instant :: now ( ) ) ; } Ok ( WaitStatus :: PtraceEvent ( pid , _sig , event ) ) => { match event { PTRACE_EVENT_FORK | PTRACE_EVENT_VFORK | PTRACE_EVENT_CLONE => { let mut new_pid : pid_t = 0 ; ptrace ( PTRACE_GETEVENTMSG , pid , ptr :: null_mut ( ) , & mut new_pid as * mut pid_t as * mut c_void ) . chain_err ( | | " " ) ? ; let name = match event { PTRACE_EVENT_FORK => " " , PTRACE_EVENT_VFORK => " " , PTRACE_EVENT_CLONE => " " , _ => unreachable ! ( ) , } ; trace ! ( " " pid name new_pid ) ; match pids . get ( & pid ) { Some ( & parent ) => { let cmdline = { let parent_data = & arena [ parent ] . data ; if parent_data . cmdline . len ( ) > 1 { parent_data . cmdline [ .. 1 ] . to_vec ( ) } else { vec ! [ ] } } ; let child = get_or_insert_pid ( new_pid , & mut arena , & mut pids ) ; arena [ child ] . data . cmdline = cmdline ; arena [ child ] . data . cwd = get_cwd ( new_pid ) ; parent . append ( child , & mut arena ) ; } None => bail ! ( " " event pid ) , } } PTRACE_EVENT_EXEC => { let mut buf = vec ! ( ) ; match pids . get ( & pid ) { Some ( & node ) => { File :: open ( format ! ( " " pid ) ) . and_then ( | mut f | f . read_to_end ( & mut buf ) ) . and_then ( | _ | { let mut cmdline = buf . split ( | & b | b == 0 ) . map ( | bytes | String :: from_utf8_lossy ( bytes ) . into_owned ( ) ) . collect :: < Vec < _ > > ( ) ; cmdline . pop ( ) ; debug ! ( " " pid cmdline ) ; arena [ node ] . data . cmdline = cmdline ; Ok ( ( ) ) } ) . chain_err ( | | " " ) ? ; } None => bail ! ( " " pid ) , } } _ => panic ! ( " " event ) , } continue_process ( pid , None ) . chain_err ( | | " " ) ? ; } Ok ( WaitStatus :: Stopped ( pid , sig ) ) => { trace ! ( " " pid sig ) ; // Sometimes we get the SIGSTOP+exit from a child before we get the clone // stop from the parent, so insert any unknown pids here so we have a better // approximation of the process start time. get_or_insert_pid ( pid , & mut arena , & mut pids ) ; let continue_sig = if sig == signal :: Signal :: SIGSTOP { None } else { Some ( sig ) } ; continue_process ( pid , continue_sig ) . chain_err ( | | " " ) ? ; } Ok ( s ) => bail ! ( " " s ) , Err ( e ) => { match e { nix :: Error :: Sys ( nix :: Errno :: EINTR ) => { /*FIXME
                            if SIGNAL_DELIVERED.swap(false, Ordering::Relaxed) {
                                println!("Active processes:");
                                print_process_tree(root, arena, |info| info.ended.is_none());
                            }
                             */ } _ => bail ! ( " " e ) , } } } } Ok ( ProcessTree { arena : arena , pids : pids , root : root , started : started , } ) }
Execute `cmd`, tracking all child processes it spawns, and return a `ProcessTree` listing
them.
Execute ` cmd ` tracking all child processes it spawns and return a ` ProcessTree ` listing them .
cmd
Command
cmdline
&[T]