How do *nix pseudo-terminals work ? What's the master/slave channel?

前端 未结 2 1700
感情败类
感情败类 2020-12-01 04:30

I want to write a simple, dumb, X terminal emulator in C on a Linux system.

At first, I just thought I would have to popen a shell and display its output. I checked

相关标签:
2条回答
  • 2020-12-01 05:10

    With respect to the master/slave part of your question, from the pty(4) man page (which is referenced from the openpty(3) man page on my system):

    A pseudo terminal is a pair of character devices, a master device and a slave device. The slave device provides to a process an interface identical to that described in tty(4). However, whereas all other devices which provide the interface described in tty(4) have a hardware device of some sort behind them, the slave device has, instead, another process manipulating it through the master half of the pseudo terminal. That is, anything written on the master device is given to the slave device as input and anything written on the slave device is presented as input on the master device.

    Man pages are your friends.

    0 讨论(0)
  • 2020-12-01 05:10

    I just tried the examples found on this tutorial, they work very fine for me and I think they are an interesting starting point for the problem.

    EDIT: The tutorial explain briefly the pseudo-terminals function. The explanation is done step by step and is followed by examples.

    The following example show how to create a new pseudo-terminal, and fork the process in two parts, one writing on the master side of the pseudo-terminal, the other reading from the slave side of the pseudo-terminal.

    #define _XOPEN_SOURCE 600 
    #include <stdlib.h> 
    #include <fcntl.h> 
    #include <errno.h> 
    #include <unistd.h> 
    #include <stdio.h> 
    #define __USE_BSD 
    #include <termios.h> 
    
    
    int main(void) 
    { 
    int fdm, fds, rc; 
    char input[150]; 
    
    fdm = posix_openpt(O_RDWR); 
    if (fdm < 0) 
    { 
    fprintf(stderr, "Error %d on posix_openpt()\n", errno); 
    return 1; 
    } 
    
    rc = grantpt(fdm); 
    if (rc != 0) 
    { 
    fprintf(stderr, "Error %d on grantpt()\n", errno); 
    return 1; 
    } 
    
    rc = unlockpt(fdm); 
    if (rc != 0) 
    { 
    fprintf(stderr, "Error %d on unlockpt()\n", errno); 
    return 1; 
    } 
    
    // Open the slave PTY
    fds = open(ptsname(fdm), O_RDWR); 
    printf("Virtual interface configured\n");
    printf("The master side is named : %s\n", ptsname(fdm));
    
    // Creation of a child process
    if (fork()) 
    { 
      // Father
    
      // Close the slave side of the PTY 
      close(fds); 
      while (1) 
      { 
        // Operator's entry (standard input = terminal) 
        write(1, "Input : ", sizeof("Input : ")); 
        rc = read(0, input, sizeof(input)); 
        if (rc > 0) 
        {
          // Send the input to the child process through the PTY 
          write(fdm, input, rc); 
    
          // Get the child's answer through the PTY 
          rc = read(fdm, input, sizeof(input) - 1); 
          if (rc > 0) 
          { 
            // Make the answer NUL terminated to display it as a string
            input[rc] = '\0'; 
    
            fprintf(stderr, "%s", input); 
          } 
          else 
          { 
            break; 
          } 
        } 
        else 
        { 
          break; 
        } 
      } // End while 
    } 
    else 
    { 
    struct termios slave_orig_term_settings; // Saved terminal settings 
    struct termios new_term_settings; // Current terminal settings 
    
      // Child
    
      // Close the master side of the PTY 
      close(fdm); 
    
      // Save the default parameters of the slave side of the PTY 
      rc = tcgetattr(fds, &slave_orig_term_settings); 
    
      // Set raw mode on the slave side of the PTY
      new_term_settings = slave_orig_term_settings; 
      cfmakeraw (&new_term_settings); 
      tcsetattr (fds, TCSANOW, &new_term_settings); 
    
      // The slave side of the PTY becomes the standard input and outputs of the child process 
      close(0); // Close standard input (current terminal) 
      close(1); // Close standard output (current terminal) 
      close(2); // Close standard error (current terminal) 
    
      dup(fds); // PTY becomes standard input (0) 
      dup(fds); // PTY becomes standard output (1) 
      dup(fds); // PTY becomes standard error (2) 
    
      while (1) 
      { 
        rc = read(fds, input, sizeof(input) - 1); 
    
        if (rc > 0) 
        { 
          // Replace the terminating \n by a NUL to display it as a string
          input[rc - 1] = '\0'; 
    
          printf("Child received : '%s'\n", input); 
        } 
        else 
        { 
          break; 
        } 
      } // End while 
    } 
    
    return 0; 
    } // main
    
    0 讨论(0)
提交回复
热议问题