Wie komme ich an dieses PTY und was kann ich damit machen?

Wie komme ich an dieses PTY und was kann ich damit machen?

Es scheint, dass ich durch eine einfache Shell-Weiterleitung /dev/ptmxein neues Pseudo-Terminal bekomme.

$ ls /dev/pts; ls /dev/pts </dev/ptmx
0  1  2  ptmx
0  1  2  3  ptmx

Es verschwindet, sobald der Prozess, dem der fd-Anspruch gehört, beendet wird /dev/ptmx, es ist jedoch ganz einfach, es beizubehalten:

$ PS1='<$(ls -1 "$@" /dev/pts/*|uniq -u)> $ ' \
  exec 3<>/dev/ptmx "$0" -si -- /dev/pts/*
</dev/pts/3> $ ls /dev/pts; exec 3>&-
0  1  2  3  ptmx
<> $ ls /dev/pts; exec 3<>/dev/ptmx
0  1  2  ptmx
</dev/pts/3> $ exit

Es sieht also so aus, als ob das einfache open()on /dev/ptmxausreicht, um ein Pseudoterminal zu erhalten. Ich schätze, das würde die Shell dazu bringen -(oder der Prozess, für den die Umleitung erfolgt)- der Eigentümer der Masterseite der Pty.

Aber wie ordne ich die Slave-Seite zu - bzw.dürfenIch weise die Slave-Seite zu? Und wenn ja, was kann ich damit machen? Kann ich die Lese-/Schreib-/Spülzeiten beeinflussen stty? Wird ein Prozess auf der Slave-Seite beim Referenzieren auf meinen neuen PTY verweisen /dev/tty?

Antwort1

Wie @muru in den Kommentaren anmerkt, scheint es also keine einfache Möglichkeit zu geben, das für Sie erstellte PTY nur mit der Shell zu verbinden. Ich habe alles bis auf den unlockpt()Teil geschafft. Laut etwas, das ich gelesen habeHierEs kann sein, dass es im Kernel einige Optionen zur Kompilierungszeit gibt, um neu erstellte PTY-Sperren zu deaktivieren, aber das wollte ich nicht. Also habe ich etwas anderes gemacht.

Ich brauchte es grantpt()eigentlich nicht. Laut der Beschreibung gefundenHieres ändert lediglich die UID/GID für /dev/pts/[num]die Gerätedatei. Aber man mountes gibt einfachere Möglichkeiten, damit umzugehen. Hier sind einige devptsMount-Optionen:

  • uid=valueUndgid=value
    • Dies setzt den Besitzer oder die Gruppe der neu erstellten PTYs auf die angegebenen Werte. Wenn nichts angegeben ist, werden sie auf die UID und GID des Erstellungsprozesses gesetzt. Wenn es beispielsweise einen tty Gruppe mit GID 5, dann gid=5werden neu erstellte PTYs zur GruppettyGruppe.

Das war auf meinem System standardmäßig schon der Fall. Aber nachdem ich das gelesen hatte, wurde mir klar, dass ich vielleicht doch etwas ändern wollte. Der nächste Abschnitt lautet:

  • ptmxmode=value
    • Legen Sie den Modus für den neuen ptmx-Geräteknoten im devptsDateisystem fest.
    • Mit der Unterstützung für mehrere Instanzen von devpts(siehe newinstanceOption oben) verfügt jede Instanz über einen privaten ptmx-Knoten im Stammverzeichnis des devptsDateisystems(normalerweise /dev/pts/ptmx).
    • Aus Kompatibilitätsgründen mit älteren Versionen des Kernels lautet der Standardmodus des neuen ptmx-Knotens 0000. ptmxmode=value Gibt einen nützlicheren Modus für den ptmx-Knoten an und wird dringend empfohlen, wenn die newinstanceOption angegeben ist.

Obwohl es auch ohne funktioniert hätte, gefiel mir die Idee und ich habe es auf 0640die empfohlene Einstellung gesetzt.Kernel-Dokumentation. Der Link zur Kernel-Dokumentation geht übrigens näher auf die newinstanceMount-Option ein – die ziemlich cool ist und es Ihnen im Grunde ermöglicht, pro Mount eine separat nach Namen sortierte Gruppe von PTYs zu erhalten /dev/ptmx.

Wie dem auch sei,etwas anderesbelief sich im Wesentlichen auf:

mount -o remount,newinstance,gid=5,ptmxmode=0640 /dev/pts
mount --bind /dev/pts/ptmx /dev/ptmx

...wie in den Kernel-Dokumenten empfohlen – siehe den Link, warum. Ich habe die Wirkung der obigen Befehle auch dauerhaft gemacht, indem ich ein paar Zeilen zu meinem hinzugefügt habe /etc/fstab.

Und...

<<\C cc -xc - -o pts
#include <stdio.h>
int main(int argc, char *argv[]) {
        if(unlockpt(0)) return 2;
        char *ptsname(int fd);
        printf("%s\n",ptsname(0));
        return argc - 1;
}
C

Dadurch wird einfach ein kleines C-Programm kompiliert, das versucht, unlockpt()seinen Standarddin aufzurufen und bei Erfolg den Namen des neu erstellten und entsperrten PTY ausgibt stdoutoder andernfalls stillschweigend 2 zurückgibt.

Sobald das erledigt war, konnte ich mein eigenes erstellenabgeschirmtProzesse wie:

exec 3<>/dev/ptmx

...um dann das Master-seitige FD in der aktuellen Shell zu erhalten...

(setsid -c "$0" -i 2>&1|tee log) <>"$(./pts <&3)" 3>&- >&0 &

Dadurch wird am anderen Ende des Pseudoterminals im Hintergrund eine interaktive Shell ausgeführt. Sie interpretiert alles, was ausgegeben wird, >&3als Benutzereingabe.

mikeserv@localhost$ echo echo hey >&3
mikeserv@localhost$ cat log
$ hey
$
mikeserv@localhost$ echo echo hey >&3
mikeserv@localhost$ cat log
$ hey
$ hey
$ 

Damit erhalte ich im Grunde einen im Hintergrund laufenden, protokollierten und interaktiven Interpreter(oder alles andere, was ich darauf ausführen möchte)ala screenohne so viel Overhead und mit jedem Dateideskriptor meiner Wahl.

Das Master-seitige FD meiner aktuellen Shell ist die einzige Möglichkeit, die Slave-seitige Eingabe zu bedienen und kann nur von meinem aktuellen Shell-Prozess geschrieben werden.(und seine Kinder). Ich kann mit dem anderen Ende per Brief kommunizieren >&3und je nach Wunsch daraus oder aus einer Protokolldatei lesen.

Und sttyfunktioniert doch auf dem Terminal:

mikeserv@localhost$ echo stty -a ">$(tty)" >&3
speed 38400 baud; rows 0; columns 0; line = 0;                                      
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc
-ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl
echoke

verwandte Informationen