title: How do *nix pseudo-terminals work ? What's the master/slave channel?
body: <p>I want to write a simple, dumb, X terminal emulator in C on a Linux system. </p>
  
  <p>At first, I just thought I would have to popen a shell and display its output.
  I checked xterm and rxvt code, and it looks a bit more complicated.</p>
  
  <p>First, I have to open a pseudo-terminal with openpty. So I look at the man page and see that openpty fills 2 file descriptors, the master and the slave.
  Both xterm and rxvt code are messy because of the system-dependent-ness of those specials files.</p>
  
  <p>I understand the termios stuff : it's just a bunch of information about the escape code of the terminal.
  What I really don't get is : what am I suppose to do with the master/slave file descriptor ?</p>
  
  <p>An example program which open a terminal, logs in, executes a "ls" on the shell would be awesome.</p>
  
  <p><em>(English is not my native language, excuse my eventual mistake)</em></p>
  
  <p>Edit:
  Here's the sample code I came up with :</p>
  
  <pre><code>#include &lt;stdlib.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;string.h&gt;
  #include &lt;pty.h&gt;
  #include &lt;utmp.h&gt;
  #include &lt;ctype.h&gt;
  
  void
  safe_print (char* s)
  {
      while(*s) { 
          if(*s == '\n')
              putchar("\n");
          else if(iscntrl(*s))
              printf("\\e(%d)", *s);
          else
              putchar(*s);
          s++;
      }
  }
  
  
  int
  main (int argc, char** argv)
  {
      char buf[BUFSIZ] = {0};
      int master;
      int ret = forkpty(&amp;master, NULL, NULL, NULL);
  
      if(ret == -1)
          puts("no fork"), exit(0);
  
      if(!ret) { 
          execl("/bin/sh", "sh", NULL);
          exit(0);
      }
  
      sleep(1); /* let the shell run */
  
  
      if(argc &gt;= 2) {
          write(master, argv[1], strlen(argv[1]));
          write(master, "\n", 1);
      } else {
          write(master, "date\n", sizeof "date\n");
      }
  
  
      while(1) {
          switch(ret = read(master, buf, BUFSIZ)) {
          case -1:
              puts("error!"); 
              exit(1);
              break;
          case 0:
              puts("nothing.."), sleep(1);
              break;
          default:
              buf[ret] = '\0';
              safe_print(buf);
  
          }
      }
  
      close(master);
  
      return 0;
  }    
  </code></pre>