Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ForkPty Always returns Parent #2402

Open
lycheeje11y opened this issue May 14, 2024 · 1 comment
Open

ForkPty Always returns Parent #2402

lycheeje11y opened this issue May 14, 2024 · 1 comment

Comments

@lycheeje11y
Copy link

I am pretty sure that I am not understanding this correctly...I am trying to open a pty for the sh shell using the nix libary with this code:

    let fd = unsafe {
        let res = nix::pty::forkpty(None, None).unwrap();
        match res.fork_result {
            ForkResult::Parent { child } => {
                println!("NOOO!")
            }
            ForkResult::Child => {
                let shell_name =
                    CStr::from_bytes_with_nul(b"sh\0").expect("Should always have null terminator");
                nix::unistd::execvp::<CString>(shell_name, &[]).unwrap();
                return;
            }
        };
        res.master
    };

However, it always returns the parent. What am I doing wrong here? I want to get forkpty to return the child, not the parent.

Note: I took a look at the src code and man page of forkpty and, from what I can make out, the function returns the parent if it runs into an error? Does that have anything to do with it?

@SteveLauC
Copy link
Member

SteveLauC commented May 19, 2024

However, it always returns the parent.

The child process will be spawned in your code and execute sh, you should be able to see it in your monitor app (search the process name sh), would you like to elaborate on it a bit what do you mean by "it always returns the parent"?

Here is a program to prove that the child process exists:

I am using Nix from git, where the return value of forkpty() differs from the one in Nix 0.28.0

use std::{thread::sleep, time::Duration};
use nix::pty::{forkpty, ForkptyResult};

fn main() {
    match unsafe {forkpty(None, None)}.unwrap() {
        ForkptyResult::Parent { child: _child, master: _master} => {
            // don't drop the master side for 1 second so that child process can
            // get its job done
            sleep(Duration::from_secs(1));
        }
        ForkptyResult::Child => {
            std::fs::write("hello_from_child", "Hi").unwrap();
        }
    };
}
$ stat hello_from_child
stat: cannot statx 'hello_from_child': No such file or directory

$ ./target/debug/rust

$ stat hello_from_child
  File: hello_from_child
  Size: 2               Blocks: 8          IO Block: 4096   regular file
Device: 0,40    Inode: 10896442    Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/   steve)   Gid: ( 1000/   steve)
Context: unconfined_u:object_r:user_home_t:s0
Access: 2024-05-19 20:04:39.014018425 +0800
Modify: 2024-05-19 20:04:39.014018425 +0800
Change: 2024-05-19 20:04:39.014018425 +0800
 Birth: 2024-05-19 20:04:39.014018425 +0800

the function returns the parent if it runs into an error

No, the interface exposed by Nix returns Err(errno), the C raw interface would return -1 and set errno to indicate the error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants