Wie tun * nichts Pseudo-Terminals arbeiten? Was ist der Master / Slave-Kanal?

StackOverflow https://stackoverflow.com/questions/476354

  •  20-08-2019
  •  | 
  •  

Frage

Ich mag einen einfachen, stumm, X-Terminal-Emulator in C auf einem Linux-System schreiben.

Zuerst dachte ich, ich würde eine Schale popen haben und seine Ausgabe an. Ich habe xterm und rxvt Code, und es sieht ein wenig komplizierter.

Zuerst muss ich mit openpty ein Pseudo-Terminal öffnen. So sehe ich den Mann an Seite und sehen, dass openpty füllt 2 Filedeskriptoren, den Master und den Slave. Sowohl xterm und rxvt Code ist chaotisch wegen der systemabhängigen Heit dieser Angebote Dateien.

Ich verstehe das termios Zeug: es ist nur ein Bündel von Informationen über den Escape-Code des Terminals. Was ich wirklich nicht bekommen, ist: was ich mit dem Master / Slave-Dateideskriptor zu tun bin nehme

Ein Beispiel-Programm, das ein Terminal zu öffnen, anmeldet, führt einen „ls“ auf der Schale wäre großartig.

(Englisch ist nicht meine Muttersprache, entschuldigen Sie meine eventuellen Fehler)

Edit: Hier ist der Beispielcode kam ich mit:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pty.h>
#include <utmp.h>
#include <ctype.h>

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(&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 >= 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;
}    
War es hilfreich?

Lösung

Im Hinblick auf den Master / Slave-Teil Ihrer Frage, von der pty (4) Manpage (die aus dem openpty (3) man-Seite auf meinem System verwiesen wird):

  

Ein Pseudo-Terminal ist ein Paar von   Zeichengeräte, ein Master-Gerät und   ein Slave-Gerät. Die Slave-Vorrichtung   liefert ein Verfahren eine Schnittstelle   identisch mit dem in tty beschrieben (4).   Während jedoch alle anderen Geräte   die bilden die Schnittstelle beschrieben   in TTY (4) ein Hardware-Gerät von   eine Art hinter ihnen, der Sklave   Gerät hat stattdessen einen anderen Prozess   Manipulieren es durch den Master   Hälfte des Pseudo-Terminal. Das heißt,   alles auf dem Master-Gerät geschrieben   wird an die Slave-Vorrichtung als Eingabe gegeben   und alles, was auf dem Slave geschrieben   Gerät wird als Eingang auf dem präsentierten   Master-Gerät.

Man-Seiten sind deine Freunde.

Andere Tipps

Ich habe gerade versucht, die auf diesem Tutorial , sie arbeiten sehr fein für mich und ich denke, dass sie ein interessanter Ausgangspunkt für das Problem sind.

EDIT: Das Tutorial erklärt kurz die Pseudo-Terminals Funktion. Die Erklärung wird Schritt für Schritt durchgeführt und wird durch Beispiele gefolgt.

Das folgende Beispiel zeigt, wie eine neuen Pseudo-Terminal und Gabel der Prozess in zwei Teilen zu schaffen, eine Schrift auf dem Master Seite der Pseudo-Terminal, die andere Lesung aus dem Slave Seite der 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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top