pub fn new<C>(config: &Config<C>, size: &SizeInfo, window_id: Option<usize>) -> Pty {
    let win_size = size.to_winsize();
    let mut buf = [0; 1024];
    let pw = get_pw_entry(&mut buf);

    let (master, slave) = make_pty(win_size);

    let default_shell = if cfg!(target_os = "macos") {
        let shell_name = pw.shell.rsplit('/').next().unwrap();
        let argv = vec![String::from("-c"), format!("exec -a -{} {}", shell_name, pw.shell)];

        Shell::new_with_args("/bin/bash", argv)
    } else {
        Shell::new(pw.shell)
    };
    let shell = config.shell.as_ref().unwrap_or(&default_shell);

    let mut builder = Command::new(&*shell.program);
    for arg in &shell.args {
        builder.arg(arg);
    }

    // Setup child stdin/stdout/stderr as slave fd of pty
    // Ownership of fd is transferred to the Stdio structs and will be closed by them at the end of
    // this scope. (It is not an issue that the fd is closed three times since File::drop ignores
    // error on libc::close.)
    builder.stdin(unsafe { Stdio::from_raw_fd(slave) });
    builder.stderr(unsafe { Stdio::from_raw_fd(slave) });
    builder.stdout(unsafe { Stdio::from_raw_fd(slave) });

    // Setup shell environment
    builder.env("LOGNAME", pw.name);
    builder.env("USER", pw.name);
    builder.env("SHELL", pw.shell);
    builder.env("HOME", pw.dir);

    if let Some(window_id) = window_id {
        builder.env("WINDOWID", format!("{}", window_id));
    }

    unsafe {
        builder.pre_exec(move || {
            // Create a new process group
            let err = libc::setsid();
            if err == -1 {
                die!("Failed to set session id: {}", io::Error::last_os_error());
            }

            set_controlling_terminal(slave);

            // No longer need slave/master fds
            libc::close(slave);
            libc::close(master);

            libc::signal(libc::SIGCHLD, libc::SIG_DFL);
            libc::signal(libc::SIGHUP, libc::SIG_DFL);
            libc::signal(libc::SIGINT, libc::SIG_DFL);
            libc::signal(libc::SIGQUIT, libc::SIG_DFL);
            libc::signal(libc::SIGTERM, libc::SIG_DFL);
            libc::signal(libc::SIGALRM, libc::SIG_DFL);

            Ok(())
        });
    }

    // Handle set working directory option
    if let Some(dir) = &config.working_directory {
        builder.current_dir(dir);
    }

    // Prepare signal handling before spawning child
    let signals = Signals::new(&[sighook::SIGCHLD]).expect("error preparing signal handling");

    match builder.spawn() {
        Ok(child) => {
            // Remember child PID so other modules can use it
            PID.store(child.id() as usize, Ordering::Relaxed);

            unsafe {
                // Maybe this should be done outside of this function so nonblocking
                // isn't forced upon consumers. Although maybe it should be?
                set_nonblocking(master);
            }

            let mut pty = Pty {
                child,
                fd: unsafe { File::from_raw_fd(master) },
                token: mio::Token::from(0),
                signals,
                signals_token: mio::Token::from(0),
            };
            pty.on_resize(size);
            pty
        },
        Err(err) => die!("Failed to spawn command '{}': {}", shell.program, err),
    }
}
/// Create a new tty and return a handle to interact with it.
Create a new tty and return a handle to interact with it.
Create a new tty and return a handle to interact with it .
pub fn new<C>(config: &Config<C>, size: &SizeInfo, window_id: Option<usize>) -> Pty {
    let win_size = size.to_winsize();
    let mut buf = [0; 1024];
    let pw = get_pw_entry(&mut buf);
    let (master, slave) = make_pty(win_size);
    let default_shell = if cfg!(target_os = "macos") {
        let shell_name = pw.shell.rsplit('/').next().unwrap();
        let argv = vec![String::from("-c"), format!("exec -a -{} {}", shell_name, pw.shell)];
        Shell::new_with_args("/bin/bash", argv)
    } else {
        Shell::new(pw.shell)
    };
    let shell = config.shell.as_ref().unwrap_or(&default_shell);
    let mut builder = Command::new(&*shell.program);
    for arg in &shell.args {
        builder.arg(arg);
    }
    // Setup child stdin/stdout/stderr as slave fd of pty
    // Ownership of fd is transferred to the Stdio structs and will be closed by them at the end of
    // this scope. (It is not an issue that the fd is closed three times since File::drop ignores
    // error on libc::close.)
    builder.stdin(unsafe { Stdio::from_raw_fd(slave) });
    builder.stderr(unsafe { Stdio::from_raw_fd(slave) });
    builder.stdout(unsafe { Stdio::from_raw_fd(slave) });
    // Setup shell environment
    builder.env("LOGNAME", pw.name);
    builder.env("USER", pw.name);
    builder.env("SHELL", pw.shell);
    builder.env("HOME", pw.dir);
    if let Some(window_id) = window_id {
        builder.env("WINDOWID", format!("{}", window_id));
    }
    unsafe {
        builder.pre_exec(move || {
            // Create a new process group
            let err = libc::setsid();
            if err == -1 {
                die!("Failed to set session id: {}", io::Error::last_os_error());
            }
            set_controlling_terminal(slave);
            // No longer need slave/master fds
            libc::close(slave);
            libc::close(master);
            libc::signal(libc::SIGCHLD, libc::SIG_DFL);
            libc::signal(libc::SIGHUP, libc::SIG_DFL);
            libc::signal(libc::SIGINT, libc::SIG_DFL);
            libc::signal(libc::SIGQUIT, libc::SIG_DFL);
            libc::signal(libc::SIGTERM, libc::SIG_DFL);
            libc::signal(libc::SIGALRM, libc::SIG_DFL);
            Ok(())
        });
    }
    // Handle set working directory option
    if let Some(dir) = &config.working_directory {
        builder.current_dir(dir);
    }
    // Prepare signal handling before spawning child
    let signals = Signals::new(&[sighook::SIGCHLD]).expect("error preparing signal handling");
    match builder.spawn() {
        Ok(child) => {
            // Remember child PID so other modules can use it
            PID.store(child.id() as usize, Ordering::Relaxed);
            unsafe {
                // Maybe this should be done outside of this function so nonblocking
                // isn't forced upon consumers. Although maybe it should be?
                set_nonblocking(master);
            }
            let mut pty = Pty {
                child,
                fd: unsafe { File::from_raw_fd(master) },
                token: mio::Token::from(0),
                signals,
                signals_token: mio::Token::from(0),
            };
            pty.on_resize(size);
            pty
        },
        Err(err) => die!("Failed to spawn command '{}': {}", shell.program, err),
    }
}
pub fn new < C > ( config : & Config < C > , size : & SizeInfo , window_id : Option < usize > ) -> Pty { let win_size = size . to_winsize ( ) ; let mut buf = [ 0 ; 1024 ] ; let pw = get_pw_entry ( & mut buf ) ; let ( master , slave ) = make_pty ( win_size ) ; let default_shell = if cfg ! ( target_os " " ) { let shell_name = pw . shell . rsplit ( '/' ) . next ( ) . unwrap ( ) ; let argv = vec ! [ String from ( " " ) format ( " " shell_name pw shell ) ] ; Shell :: new_with_args ( " " , argv ) } else { Shell :: new ( pw . shell ) } ; let shell = config . shell . as_ref ( ) . unwrap_or ( & default_shell ) ; let mut builder = Command :: new ( & * shell . program ) ; for arg in & shell . args { builder . arg ( arg ) ; } // Setup child stdin/stdout/stderr as slave fd of pty // Ownership of fd is transferred to the Stdio structs and will be closed by them at the end of // this scope. (It is not an issue that the fd is closed three times since File::drop ignores // error on libc::close.) builder . stdin ( unsafe { Stdio :: from_raw_fd ( slave ) } ) ; builder . stderr ( unsafe { Stdio :: from_raw_fd ( slave ) } ) ; builder . stdout ( unsafe { Stdio :: from_raw_fd ( slave ) } ) ; // Setup shell environment builder . env ( " " , pw . name ) ; builder . env ( " " , pw . name ) ; builder . env ( " " , pw . shell ) ; builder . env ( " " , pw . dir ) ; if let Some ( window_id ) = window_id { builder . env ( " " , format ! ( " " window_id ) ) ; } unsafe { builder . pre_exec ( move | | { // Create a new process group let err = libc :: setsid ( ) ; if err == - 1 { die ! ( " " io Error last_os_error ( ) ) ; } set_controlling_terminal ( slave ) ; // No longer need slave/master fds libc :: close ( slave ) ; libc :: close ( master ) ; libc :: signal ( libc :: SIGCHLD , libc :: SIG_DFL ) ; libc :: signal ( libc :: SIGHUP , libc :: SIG_DFL ) ; libc :: signal ( libc :: SIGINT , libc :: SIG_DFL ) ; libc :: signal ( libc :: SIGQUIT , libc :: SIG_DFL ) ; libc :: signal ( libc :: SIGTERM , libc :: SIG_DFL ) ; libc :: signal ( libc :: SIGALRM , libc :: SIG_DFL ) ; Ok ( ( ) ) } ) ; } // Handle set working directory option if let Some ( dir ) = & config . working_directory { builder . current_dir ( dir ) ; } // Prepare signal handling before spawning child let signals = Signals :: new ( & [ sighook :: SIGCHLD ] ) . expect ( " " ) ; match builder . spawn ( ) { Ok ( child ) => { // Remember child PID so other modules can use it PID . store ( child . id ( ) as usize , Ordering :: Relaxed ) ; unsafe { // Maybe this should be done outside of this function so nonblocking // isn't forced upon consumers. Although maybe it should be? set_nonblocking ( master ) ; } let mut pty = Pty { child , fd : unsafe { File :: from_raw_fd ( master ) } , token : mio :: Token :: from ( 0 ) , signals , signals_token : mio :: Token :: from ( 0 ) , } ; pty . on_resize ( size ) ; pty } , Err ( err ) => die ! ( " " shell program err ) , } }
Create a new tty and return a handle to interact with it.
Create a new tty and return a handle to interact with it .
config
&Config<C>
size
&SizeInfo
window_id
Option<usize>