wie benutzt man pseudoterminals?

OP #7898793
Lesenswert?

schönen Freitag miteinander!

Programm1 redet normalerweise per /dev/ttyUSBx mit einer Hardware. Jetzt soll Programm2 diese Hardware simulieren. Prog1 kann einen symlink (z.B. "/tmp/hardware") für die Schnittstelle benutzen, dann sieht es sehr einfach aus:

1
pts = open("/dev/ptmx", O_RDONLY);
2
path = ptsname (pts);
3
grantpt (pts);
4
unlockpt (pts);
5
symlink (path, "/tmp/hardware");

so kann Prog1 sein normales open("/tmp/hardware") machen.

Jetzt muss man "nur noch" dafür sorgen, dass der Link entfernt wird, wenn Prog2 beendet wird. atexit() funktioniert dafür nur meistens. Ja, Prog1 könnte das pty in /proc/$(pidof Prog2)/fd/ suchen, aber wie macht man das normalerweise?

#7899217
Lesenswert?

Den Symlink könnte man früher löschen - der kann weg sobald Prog1 sein open() call ausgeführt hat.

Ob das in der Praxis funktioniert ist zweifelhaft.

TTYUSB kennt noch die für UART/RS232 typischen Schnittstellenparameter und deren Syscalls. Die funktionieren auf Dateien oder named Pipes nicht.

OP #7899251
Lesenswert?

Jim M. schrieb:

Den Symlink könnte man früher löschen - der kann weg sobald Prog1 sein open() call ausgeführt hat.

Gute Idee, danke!

Ob das in der Praxis funktioniert ist zweifelhaft.

Meinst du das Link-löschen oder die Schnittstellenparameter? Es bleibt ein kleines Restrisiko: Prog2 startet, Prog1 aber nicht, Prog2 erwischt einen Segfault, Prog1 startet und findet den kaputten Link. Irgendwas ist immer; hauptsächlich wundert mich, dass es dafür scheinbar keinen Mechanismus gibt. So in der Art, wie z.B. Speicher garantiert freigegeben wird, egal, wie das Programm beendet wird.

Die ioctl() Syscalls funktionieren, praktisch als NOP. Nur das Timing ist natürlich völlig anders, dagegen reicht mir in diesem speziellen Fall ein usleep().

#7899412
Lesenswert?

Jim M. schrieb:

Den Symlink könnte man früher löschen - der kann weg sobald Prog1 sein open() call ausgeführt hat.

Ob das in der Praxis funktioniert ist zweifelhaft.

Das gilt eigentlich für alle was über Filedescriptoren angesprochen wird. Mann kann das Objekt (File, (Sym)Link, Gerät, ...) auf Filesystem-Ebene hinterrücks löschen. Das Objekt bleibt trotzdem so lange erhalten bis der letzte Filedescriptor drauf zu gemacht wird.

Eine uralte, schon zu UNIX-Zeiten beliebte Technik um zum Beispiel temporäre Dateien automatisch zu löschen wenn der Prozess endet. Datei öffnen, Filedescriptor brav behalte, Datei im Filesystem löschen, frisch und fröhlich mit der nun unsichtbaren Datei über den Filedescriptor arbeiten. Der Prozess endet und Linux räumt erst dann die Datei ab.

Gast #7899429
Lesenswert?

Hannes J. schrieb:

Eine uralte, schon zu UNIX-Zeiten beliebte Technik um zum Beispiel temporäre Dateien automatisch zu löschen wenn der Prozess endet. Datei öffnen, Filedescriptor brav behalte, Datei im Filesystem löschen, frisch und fröhlich mit der nun unsichtbaren Datei über den Filedescriptor arbeiten. Der Prozess endet und Linux räumt erst dann die Datei ab.

Oder, wenn der Prozess weiter und weiter auf /tmp schreibt, gibt es eine panic und der Systemverwalter steht in Deinem Buero... Der schoene neue Convex-Supercomputer sollte fuer etwas gut sein...

#7899561
Lesenswert?

Ja, Prog1 könnte das pty in /proc/$(pidof Prog2)/fd/ suchen, aber wie macht man das normalerweise?

Da würde es aber doch nur das ptm, nicht das pts, finden.

Falls Programm 2 von Program 1 gestartet wird, könnte man Program 2 ein FD von Program 1 übergeben. Man könnte das pts öffnen und als FD 0,1,2 (stdin, stdout, stderr) setzen. Oder man könnte eine environment Variable oder einen Parameter setzen, und ihm so mitteilen, wo das pts zu finden ist.

(Mit /proc/self/fd/N kann man für FDs auch einen Dateipfad angeben. Aber ein open da drauf gibt eine neue File Description (nicht nur einen neuen File Descriptor). Beim pts kein Problem, bei (gelöschten) Dateien auch nicht. Aber z.B. bei einem fd auf ein ptm von /dev/ptmx bekäme man ein neues pts).

OP #7900123
Lesenswert?

Daniel A. schrieb:

Ja, Prog1 könnte das pty in /proc/$(pidof Prog2)/fd/ suchen, aber wie macht man das normalerweise?

Da würde es aber doch nur das ptm, nicht das pts, finden.

Stimmt auch wieder. Wenn man einem vorhandenen Programm eine Hardware vortäuschen will, kommt sowas ja sowieso nicht in Frage, da ist ein symlink vernünftig. Und im Normalfall, wenn beide Programme zusammenarbeiten, funktioniert ja alles automatisch richtig. Dankeschön!

#7900788
Lesenswert?

Im Prinzip sollte kein Programm in einen segfault laufen, das wäre eigentlich das Maß der Dinge.

Man kann ansonsten alle anderen Sigs abfangen und abhandeln, dann wäre jede andere Möglichkeit den Symlink doch zu löschen abgedeckt.

Einen kritischen Segfault kann man verhindern indem man es richtig programmiert. man könnte auch bei jedem start des "Programm2" einen vorhandenen symlink löschen. Somit gäbe es keinen unlösbaren Worst case.

#7903805
Lesenswert?

Nur um das nochmal mit Beispiel gezeigt zu haben, du könntest das Programm, welches das TTY braucht, von dem starten lassen, welches es bereitstellt.

1
$ ./terminal_providing_program bash -c 'echo "Hello World" >"$MY_DEVICE_PATH"'
2
Got data 13: Hello World..
3
Child program exited
4
Stopping program!
5
$ ./terminal_providing_program bash -c 'exec <>"$MY_DEVICE_PATH" >&0 2>&0; echo test'
6
Got data 6: test..
7
Child program exited
8
Stopping program!
9
$ ./terminal_providing_program bash -c 'exec {fd}<>"$MY_DEVICE_PATH"; export MY_DEVICE_FD="$fd"; bash -c "echo 123 >&$MY_DEVICE_FD"'

Kann man als Pfad, über fixe FDs (z.B. stdin/stdout), oder per erstem freien FD + ne env variable, übergeben.

So braucht man keine Symlinks, und es bleibt nachher auch nichts zurück.

Angehängte Dateien:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren