Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Pseudoterminal funkioniert auf einem bestimmten System nicht

8 views
Skip to first unread message

Edzard Egberts

unread,
Jan 26, 2012, 6:06:47 AM1/26/12
to
Ich habe ein Programm, das über Pseudoterminal Befehle ausführt (z.B.
ifconfig). Unter Fedora funktioniert das wunderbar, auf einem kleinen
Slackware-System aber nicht:

Wenn ich das Programm im Terminal ausführe, meldet es die korrekte
Erzeugung des Pseudoterminals, das Pseudoterminal meldet aber keinen
Prompt und die Befehle werden nicht ausgeführt.

Im Moment weiß ich nicht mal so recht, wo ich den Fehler suchen soll -
brauche ich eine bestimmte Shell oder so etwas? Jeder Ratschlag (im
Sinne von gut geraten ;o), ist willkommen.

Edzard Egberts

unread,
Jan 26, 2012, 8:00:28 AM1/26/12
to
Edzard Egberts schrieb:
> Ich habe ein Programm, das über Pseudoterminal Befehle ausführt (z.B.
> ifconfig). Unter Fedora funktioniert das wunderbar, auf einem kleinen
> Slackware-System aber nicht:
>
> Wenn ich das Programm im Terminal ausführe, meldet es die korrekte
> Erzeugung des Pseudoterminals, das Pseudoterminal meldet aber keinen
> Prompt und die Befehle werden nicht ausgeführt.

Angehängt die Klasse, wird sowieso Zeit, dass ein
C++-Pseudoterminal-Code in die Welt gesetzt wird. Die C-Versionen fand
ich alle etwas unhandlich.

Verwendung der Klasse:

#include "pseudoterminal.h"


pseudoterminal PT;
if (PT.Valid())
{
PT.Write("ifconfig eth0:1 10.0.0.10");
string Ans;
do {
Ans= PT.Readline(500);
if (Ans== PT.Prompt()) cout << "Ok" << endl;
else cout << "Ans: " << Ans << endl;
} while (!Ans.empty());
}
else cout << PT.Error() << endl;

Habe ich da einfach nur im C-Teil etwas verpatzt, oder gibt es Umstände,
unter denen das nicht funktionieren kann?
pseudoterminal.h
pseudoterminal.cpp

Edzard Egberts

unread,
Jan 26, 2012, 8:06:40 AM1/26/12
to
Edzard Egberts schrieb:
> pseudoterminal PT;
> if (PT.Valid())
> {
> PT.Write("ifconfig eth0:1 10.0.0.10");
> string Ans;
> do {
> Ans= PT.Readline(500);
> if (Ans== PT.Prompt()) cout << "Ok" << endl;
> else cout << "Ans: " << Ans << endl;
> } while (!Ans.empty());

} while (Ans!= PT.Prompt() && !Ans.empty());

Sorry, habe den Code heute morgen erst wieder hervorgekramt...

Enrik Berkhan

unread,
Jan 26, 2012, 8:59:28 AM1/26/12
to
Edzard Egberts <ed...@tantec.de> wrote:
> Im Moment weiß ich nicht mal so recht, wo ich den Fehler suchen soll -
> brauche ich eine bestimmte Shell oder so etwas? Jeder Ratschlag (im
> Sinne von gut geraten ;o), ist willkommen.

Rufe das Programm auf beiden Systemen mal mit `strace -f' auf und achte
auf die Unterschiede.

Gruß,
Enrik

Edzard Egberts

unread,
Jan 27, 2012, 8:50:31 AM1/27/12
to
Enrik Berkhan schrieb:
Das habe ich gemacht und das ergibt für das gleich Programm auch
unterschiedliche Ausgaben, aber da hänge ich schon wieder - was bedeutet
das?

Diese Variante funktioniert:

execve("./test", ["./test"], [/* 50 vars */]) = 0
brk(0) = 0x80ea000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
0) = 0xb7899000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or
directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=112520, ...}) = 0
mmap2(NULL, 112520, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb787d000
close(3) = 0
[...]

Diese geht nicht:

execve("./test", ["./test"], [/* 25 vars */]) = 0
brk(0) = 0x804d000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or
directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=12477, ...}) = 0
mmap2(NULL, 12477, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb806f000
close(3)
[...]

Da fehlt also ein mmap2-Aufruf in der dritten Zeile und gleich die erste
Zeile ist unterschiedlich. Falls das nichts zu bedeuten hat, hänge ich
die gesamte Ausgabe an. Falls das etwas zu bedeuten hat - was denn nur?
test_err.txt
main.cpp
test_ok.txt

Edzard Egberts

unread,
Jan 27, 2012, 9:04:47 AM1/27/12
to
Ups, peinlich, die "test_err.txt" war falsch. Da habe ich eine falsche
Datei erwischt, keine Ahnung, wie mir das passiert ist.

Im Anhang der zweite Versuch.
test_err.txt

Rainer Weikusat

unread,
Jan 27, 2012, 11:15:29 AM1/27/12
to
Edzard Egberts <ed...@tantec.de> writes:
> Enrik Berkhan schrieb:
>> Edzard Egberts<ed...@tantec.de> wrote:
>>> Im Moment weiß ich nicht mal so recht, wo ich den Fehler suchen soll -
>>> brauche ich eine bestimmte Shell oder so etwas? Jeder Ratschlag (im
>>> Sinne von gut geraten ;o), ist willkommen.
>>
>> Rufe das Programm auf beiden Systemen mal mit `strace -f' auf und achte
>> auf die Unterschiede.
>
> Das habe ich gemacht und das ergibt für das gleich Programm auch
> unterschiedliche Ausgaben, aber da hänge ich schon wieder - was
> bedeutet das?

Das Du strace und nicht strace -f benutzt hast. Deswegen fehlt die
trace-Ausgabe fuer den 'Sklavenprozess' (das klingt nicht wirklich
nett :-).


Enrik Berkhan

unread,
Jan 30, 2012, 5:54:46 AM1/30/12
to
Edzard Egberts <ed...@tantec.de> wrote:
> Nächster Versuche (sorry für die dicken Anhänge): Also in test_err ist
> der Fehler in Zeile 858 schon aufgetreten: Die Befehlssequenz scheint
> mir in Ordnung, aber die Datei wird nicht angelegt. In test_ok ist das
> die Zeile 3369 - irgendetwas in den fehlenden 2511 Zeilen war wohl
> wichtig. Bestimmt muss ich mir das nur durchlesen und der Fehler ist
> offensichtlich, leider mangelt es etwas am Textverständnis, bzw. am
> Verständnis allgemein. "Befehl ausgeben und Ergebnis zurücklesen" habe
> ich mir etwas einfacher vorgestellt. Oder bin ich der Einzige, der
> glaubt ein Pseudoterminal benutzen zu müssen und wird das normalerweise
> mit einem "system"-Befehl und irgendeiner Umleitung der Ausgaben
> gemacht? Mit dem Zeugs bin ich ja schon länger dran und das ist
> irgendwie schmerzhaft...

Sieht doch alles korrekt aus. Sei dir bewusst, dass du mit deiner
pty-Methode eine "authentische interaktive" Umgebung für deine Shell
erzeugst. Möglicherweise wechselt ein Login-Skript auf dem einen System
das Arbeitsverzeichnis nach $HOME, auf dem anderen nicht oder so etwas.

Kannst in deine Test-Befehls-Sequenz ja mal ein `pwd' einbauen.

Ansonsten, falls du eigentlich gar keine interaktive Umgebung simulieren
willst, sieh dir system(3), popen(3), fork(2)+pipe(2) etc. an.

Gruss,
Enrik

Rainer Weikusat

unread,
Jan 30, 2012, 8:23:25 AM1/30/12
to
Edzard Egberts <ed...@tantec.de> writes:
> Rainer Weikusat schrieb:
>> Edzard Egberts<ed...@tantec.de> writes:
>>> Das habe ich gemacht und das ergibt für das gleich Programm auch
>>> unterschiedliche Ausgaben, aber da hänge ich schon wieder - was
>>> bedeutet das?
>>
>> Das Du strace und nicht strace -f benutzt hast. Deswegen fehlt die
>> trace-Ausgabe fuer den 'Sklavenprozess' (das klingt nicht wirklich
>> nett :-).
>
> ARGH! Zuerst habe ich es ja richtig gemacht, aber dann ließ sich die
> Ausgabe nicht in eine Datei umleiten (reine Schikane, oder ist die
> Ausgabe auf stderr irgendwie nötig?).

Sie ist insofern nuetzlich als das man 'normale' Programm-Ausgaben
weiterhin auf stdout zu sehen bekommt. Dh man kann zB sowas machen:

strace bc -l 2>x

Das Programm (ein ausgesprochen nuetzliches interaktives
Rechenprogramm) eine Weile benutzen und sich danach die trace-Ausgabe
in der Datei x ansehen.

[...]

> Nächster Versuche (sorry für die dicken Anhänge): Also in test_err ist
> der Fehler in Zeile 858 schon aufgetreten: Die Befehlssequenz scheint
> mir in Ordnung, aber die Datei wird nicht angelegt. In test_ok ist das
> die Zeile 3369 - irgendetwas in den fehlenden 2511 Zeilen war wohl
> wichtig.

Die Datei wurde definitiv in beiden Faellen angelegt:

,----
| [rw@sapphire]/tmp $grep ed_test test_ok.txt
| 3057 write(3, "echo Hallo Ed > ed_test.txt\n", 28 <unfinished ...>
| 3057 <... read resumed> "echo Hallo Ed > ed_test.txt\r\n", 256) = 29
| 3057 write(1, "Ans: echo Hallo Ed > ed_test.txt"..., 33 <unfinished ...>
| 3058 open("ed_test.txt", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
`----

,----
| [rw@sapphire]/tmp $grep ed_test test_err.txt
| 1769 write(3, "echo Hallo Ed > ed_test.txt\n"..., 28) = 28
| 1769 read(3, "echo Hallo Ed > ed_test.txt\r\n"..., 256) = 29
| 1769 write(1, "Ans: echo Hallo Ed > ed_test.txt\n"..., 33 <unfinished ...>
| 1770 open("ed_test.txt", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
`----

Edzard Egberts

unread,
Jan 30, 2012, 9:01:07 AM1/30/12
to
Enrik Berkhan schrieb:
> Sieht doch alles korrekt aus. Sei dir bewusst, dass du mit deiner
> pty-Methode eine "authentische interaktive" Umgebung für deine Shell
> erzeugst. Möglicherweise wechselt ein Login-Skript auf dem einen System
> das Arbeitsverzeichnis nach $HOME, auf dem anderen nicht oder so etwas.
>
> Kannst in deine Test-Befehls-Sequenz ja mal ein `pwd' einbauen.

Das ist es wohl nicht, das Verzeichnis stimmt. Aber irgend so etwas
abartiges muss es schon sein, weil die Befehle auf dem aktuellen
Terminal ausgegeben werden, statt dass sie vom Pseudoterminal
verarbeitet werden.

> Ansonsten, falls du eigentlich gar keine interaktive Umgebung simulieren
> willst, sieh dir system(3), popen(3), fork(2)+pipe(2) etc. an.

Ich möchte einen Shell-Befehl ausgeben, z.B. "pwd" und die Antwort
weiterverarbeiten, bei pwd eben den Pfad. "system" informiert mich zwar
darüber, dass der pwd-Befehl erfolgreich ausgeführt wurde, aber damit
habe ich noch lange keinen Pfad. In eine Datei oder Pipe umleiten geht
auch nicht, weil das Umleiten nicht immer geht. Dieses ganze Konzept mit
Ausgaben weiter leiten ist zwar eine tolle Idee, kann ich aber im
praktischen Einsatz vergessen, weil von mir benötigte Programme ihre
Ausgaben oft auf unerfindlichem Wege produzieren und sich nicht umleiten
lassen. Auf so einen Murks bin ich hier gerade noch am Freitag
hereingefallen und außer stderr muss es noch andere Wege geben.

Das ist ein einziges widerliches Gemurkse, aber alles auf API-Ebene
selber machen, ist so aufwändig! Aber wohl auch die einzige Möglichkeit,
dass Sachen wirklich funktionieren. :o(

Edzard Egberts

unread,
Jan 30, 2012, 9:51:42 AM1/30/12
to
Rainer Weikusat schrieb:
> Edzard Egberts<ed...@tantec.de> writes:

>> Nächster Versuche (sorry für die dicken Anhänge): Also in test_err ist
>> der Fehler in Zeile 858 schon aufgetreten: Die Befehlssequenz scheint
>> mir in Ordnung, aber die Datei wird nicht angelegt. In test_ok ist das
>> die Zeile 3369 - irgendetwas in den fehlenden 2511 Zeilen war wohl
>> wichtig.
>
> Die Datei wurde definitiv in beiden Faellen angelegt:

Ich werd' zum Elch:

Mit "strace -f -o ptr.txt ./test" wird die Datei gelegentlich angelegt
(im Beispiel unten beim zw, dagegen legt ein direkter Aufruf "./test"
oder ein anderer strace-Aufruf ("strace ./test", "strace -f ./test",
"strace -o ptr.txt ./test") die Datei nicht an. Auch nicht, wenn man
einen Pfad angibt. Auch nicht, wenn man das Programm an mehreren Stellen
mit sleep() verziert. Oh Mann, ohne die Kabel könnte ich das kleine Ding
soo schön an die Wand werfen! ;o(

root@ccam01000:/home/ed/Cpp/test_biff/Debug# strace -o ptr.txt ./test

Ans: echo Hallo Ed > /root/ed_test.txt

Ok

root@ccam01000:/home/ed/Cpp/test_biff/Debug# ls /root

start_server*

root@ccam01000:/home/ed/Cpp/test_biff/Debug# strace -f -o ptr.txt ./test

Ans: root@ccam01000:/home/ed/Cpp/test_biff/Debug# PS1="*0k>"

Ok

root@ccam01000:/home/ed/Cpp/test_biff/Debug# ls /root

start_server*

root@ccam01000:/home/ed/Cpp/test_biff/Debug# strace -f -o ptr.txt ./test

Ans: echo Hallo Ed > /root/ed_test.txt

Ans: root@ccam01000:/home/ed/Cpp/test_biff/Debug# PS1="*0k>"

Ans: *0k>echo Hallo Ed > /root/ed_test.txt

Ok

root@ccam01000:/home/ed/Cpp/test_biff/Debug# ls /root

ed_test.txt start_server*

Volker Birk

unread,
Jan 30, 2012, 9:55:28 AM1/30/12
to
Edzard Egberts <ed...@tantec.de> wrote:
> Ich möchte einen Shell-Befehl ausgeben, z.B. "pwd" und die Antwort
> weiterverarbeiten, bei pwd eben den Pfad. "system" informiert mich zwar
> darüber, dass der pwd-Befehl erfolgreich ausgeführt wurde, aber damit
> habe ich noch lange keinen Pfad. In eine Datei oder Pipe umleiten geht
> auch nicht, weil das Umleiten nicht immer geht.

Na, bei pwd schon. Wobei pwd ja auch unnötig ist, siehe getcwd(3).

> Dieses ganze Konzept mit
> Ausgaben weiter leiten ist zwar eine tolle Idee, kann ich aber im
> praktischen Einsatz vergessen, weil von mir benötigte Programme ihre
> Ausgaben oft auf unerfindlichem Wege produzieren und sich nicht umleiten
> lassen.

Es gibt Programme, die sprechen direkt mit dem Terminal. Um solche
Programme fernzusteuern, gibt es expect(1).

> Das ist ein einziges widerliches Gemurkse, aber alles auf API-Ebene
> selber machen, ist so aufwändig! Aber wohl auch die einzige Möglichkeit,
> dass Sachen wirklich funktionieren. :o(

Üblicherweise programmiert man in C dann doch, indem man die API
benutzt. Sonst benutz doch eine Scriptsprache wie Python oder Perl.

Viele Grüsse,
VB.
--
"If /dev/null is fast in web scale I will use it."

http://www.mongodb-is-web-scale.com/

Edzard Egberts

unread,
Jan 30, 2012, 10:26:07 AM1/30/12
to
Volker Birk schrieb:
> Edzard Egberts<ed...@tantec.de> wrote:
>> Ich möchte einen Shell-Befehl ausgeben, z.B. "pwd" und die Antwort
>> weiterverarbeiten, bei pwd eben den Pfad. "system" informiert mich zwar
>> darüber, dass der pwd-Befehl erfolgreich ausgeführt wurde, aber damit
>> habe ich noch lange keinen Pfad. In eine Datei oder Pipe umleiten geht
>> auch nicht, weil das Umleiten nicht immer geht.
>
> Na, bei pwd schon. Wobei pwd ja auch unnötig ist, siehe getcwd(3).

Ich habe das irrtümlich für ein unmittelbar einleuchtendes Beispiel zur
Frage "warum interaktiv?" gehalten.

> Es gibt Programme, die sprechen direkt mit dem Terminal. Um solche
> Programme fernzusteuern, gibt es expect(1).

Na ja, http://en.wikipedia.org/wiki/Expect: "It uses Unix pseudo
terminals". Bin mir nicht so sicher, ob das eine Alternative ist.
BTW. Was ist das eigentlich für ein Parameter "expect(1)"? Der Enrik hat
auch schon so komische Sachen geschrieben.

>> Das ist ein einziges widerliches Gemurkse, aber alles auf API-Ebene
>> selber machen, ist so aufwändig!
>
> Üblicherweise programmiert man in C dann doch, indem man die API
> benutzt. Sonst benutz doch eine Scriptsprache wie Python oder Perl.

Das Problem ist "Alles selber machen" - hinter manchen Shell-Befehlen
oder Kommandozeilen-Tools stecken API-Aufrufe für Mannjahre an
Programmierzeit, warum also soll man die nicht auch aus C++ aufrufen
können? Ich bin mir sogar ziemlich sicher, dass man das können sollte,
Unix-Tools und so...

Enrik Berkhan

unread,
Jan 30, 2012, 10:54:41 AM1/30/12
to
Edzard Egberts <ed...@tantec.de> wrote:
> Ich werd' zum Elch:

Wie hypsch :)

> Mit "strace -f -o ptr.txt ./test" wird die Datei gelegentlich angelegt
> (im Beispiel unten beim zw, dagegen legt ein direkter Aufruf "./test"
> oder ein anderer strace-Aufruf ("strace ./test", "strace -f ./test",
> "strace -o ptr.txt ./test") die Datei nicht an. Auch nicht, wenn man
> einen Pfad angibt. Auch nicht, wenn man das Programm an mehreren Stellen
> mit sleep() verziert. Oh Mann, ohne die Kabel könnte ich das kleine Ding
> soo schön an die Wand werfen! ;o(

Das riecht nach race condition.

Wenn ich mir deine Logs nochmal ansehe, fällt mir auf, dass deine PTYs
auf "local echo" stehen. Daher werden deine Kommandos auch zweimal
"geechot". Behandelst du das garantiert richtig? Änder das evtl. mal.

Gruß,
Enrik

Volker Birk

unread,
Jan 30, 2012, 11:26:23 AM1/30/12
to
Edzard Egberts <ed...@tantec.de> wrote:
> Was ist das eigentlich für ein Parameter "expect(1)"? Der Enrik hat
> auch schon so komische Sachen geschrieben.

Das bedeutet, dass Du die Dokumentation zu expect im Unix-Handbuch in
Kapitel 1 findest.

Auf der Kommandozeile eines Unix- oder GNU/Linux-Systems kannst Du dann
die entsprechende Dokumentation z.B. mit

$ man 1 expect

aufrufen.

> hinter manchen Shell-Befehlen oder Kommandozeilen-Tools stecken
> API-Aufrufe für Mannjahre an Programmierzeit, warum also soll man die
> nicht auch aus C++ aufrufen können? Ich bin mir sogar ziemlich sicher,
> dass man das können sollte, Unix-Tools und so...

Es gibt auch eine Menge Bibliotheken.

Enrik Berkhan

unread,
Jan 30, 2012, 1:49:26 PM1/30/12
to
Edzard Egberts <ed...@tantec.de> wrote:
> Ich habe ein Programm, das über Pseudoterminal Befehle ausführt (z.B.
> ifconfig). Unter Fedora funktioniert das wunderbar, auf einem kleinen
> Slackware-System aber nicht:

Um mal zurück an den Anfang zu gehen: gerade `ifconfig' ist
normalerweise nicht interaktiv. Es braucht ein paar Argumente auf der
Kommandozeile und du interessiert dich für den Rückgabewert, evtl. noch
für die Ausgabe. Dafür braucht man kein Pseudoterminal.

Einfaches Beispiel:

--- 8< ---
#include <stdio.h>
#include <stdlib.h>

int main(void) {
FILE *cmd;
static char buf[1024];
size_t len;
int status;

cmd = popen("exec /sbin/ifconfig eth0 2>&1 </dev/null", "r");
if (!cmd) {
perror("popen");
exit(1);
}

while ((len = fread(buf, 1, sizeof buf, cmd)) > 0) {
fwrite(buf, 1, len, stdout);
}

status = pclose(cmd);
if (-1 == status) {
perror("pclose");
exit(1);
}

printf("exit value: %d\n", WEXITSTATUS(status));


return 0;
}
--- >8 ---

Mit popen(3) geht das Kommando noch "durch eine Shell", muss man
berücksichtigen. Die Auswertung des exit status ist nicht vollständig und auch
nicht portabel, AFAIK.

Kommst du denn damit nicht hin?

Gruß,
Enrik

Edzard Egberts

unread,
Jan 31, 2012, 2:35:45 AM1/31/12
to
Volker Birk schrieb:
> Edzard Egberts<ed...@tantec.de> wrote:
>> Was ist das eigentlich für ein Parameter "expect(1)"? Der Enrik hat
>> auch schon so komische Sachen geschrieben.
>
> Das bedeutet, dass Du die Dokumentation zu expect im Unix-Handbuch in
> Kapitel 1 findest.
>
> Auf der Kommandozeile eines Unix- oder GNU/Linux-Systems kannst Du dann
> die entsprechende Dokumentation z.B. mit
>
> $ man 1 expect

"No manual entry". Müsste das nicht in der stdlib sein? Dass hier
irgendwo Dokumentation von Bibliotheksaufrufen herumfliegt, wäre mir neu
(könnte ich aber gebrauchen).

> Es gibt auch eine Menge Bibliotheken.

Sehe ich das richtig, dass Du die Unix-Befehle für C/C++-Programme für
unbrauchbar hältst und sowieso niemand ein Pseudoterminal verwendet?
Darauf scheint mir die Sache hinauszulaufen - überall steht, wofür das
gut sein soll, aber ich habe schon alleine Wochen gebraucht, um einen
lauffähigen Code zu finden (bzw. genug Hinweise, um mir einen
zusammenzubasteln - einen zusammenhängenden, lauffähigen Code für so
etwas, habe ich nirgendwo gefunden).

Edzard Egberts

unread,
Jan 31, 2012, 2:35:46 AM1/31/12
to
Enrik Berkhan schrieb:
> Edzard Egberts<ed...@tantec.de> wrote:
>> Ich habe ein Programm, das über Pseudoterminal Befehle ausführt (z.B.
>> ifconfig). Unter Fedora funktioniert das wunderbar, auf einem kleinen
>> Slackware-System aber nicht:
>
> Um mal zurück an den Anfang zu gehen: gerade `ifconfig' ist
> normalerweise nicht interaktiv. Es braucht ein paar Argumente auf der
> Kommandozeile und du interessiert dich für den Rückgabewert, evtl. noch
> für die Ausgabe. Dafür braucht man kein Pseudoterminal.

Stimmt, damit ich wenigstens ein paar Kleinigkeiten machen konnte, habe
ich den system-Befehl benutzt. Beispiele werde hier aber irgendwie zu
eng gesehen, kennst Du den Canon-Capture-Treiber?

Naja, Timeout! Meine Zeitpläne sind inzwischen völlig zusammengebrochen
und das Gerät wird jetzt mit alter Software ausgeliefert. Warum ich's
nicht geregelt kriege, kann ich auch nicht erklären, macht gerade genau
so viel Spaß, wie Programmierung unter Windows. :o(

Volker Birk

unread,
Jan 31, 2012, 2:55:21 AM1/31/12
to
Edzard Egberts <ed...@tantec.de> wrote:
>> $ man 1 expect
> "No manual entry".

Dann ist wohl zumindest die Dokumentation zu expect nicht installiert,
oder expect ist nicht installiert.

> Müsste das nicht in der stdlib sein? Dass hier irgendwo Dokumentation
> von Bibliotheksaufrufen herumfliegt, wäre mir neu (könnte ich aber
> gebrauchen).

expect ist ein Programm.

>> Es gibt auch eine Menge Bibliotheken.
> Sehe ich das richtig, dass Du die Unix-Befehle für C/C++-Programme für
> unbrauchbar hältst und sowieso niemand ein Pseudoterminal verwendet?

Unbrauchbar ist etwas hart formuliert, aber die API ist in jedem Falle
vorzuziehen. Pseudoterminals sind gängig.

Enrik Berkhan

unread,
Jan 31, 2012, 4:52:07 AM1/31/12
to
Edzard Egberts <ed...@tantec.de> wrote:
> Stimmt, damit ich wenigstens ein paar Kleinigkeiten machen konnte, habe
> ich den system-Befehl benutzt. Beispiele werde hier aber irgendwie zu
> eng gesehen, kennst Du den Canon-Capture-Treiber?

Nein, ich kenne _den_ Canon-Capture-Treiber nicht, was soll das denn
sein? Wenn der nix taugt bzw. nicht Open Source ist, würde ich den halt
meiden.

Gruß,
Enrik

Rainer Weikusat

unread,
Jan 31, 2012, 10:59:29 AM1/31/12
to
Edzard Egberts <ed...@tantec.de> writes:

[...]

>> Es gibt auch eine Menge Bibliotheken.
>
> Sehe ich das richtig, dass Du die Unix-Befehle für C/C++-Programme für
> unbrauchbar hältst und sowieso niemand ein Pseudoterminal verwendet?

Jegliche Form von Netzwerk-Login benutzt notwendigerweise
Pseudoterminals die (soweit mir das bekannt ist) zu genau diesem
Zweck irgendwann in den fruehen 1980ern (vermutlich 81, 82 oder 83)
erfunden wurden. Genaugenommen braucht man die immer, wenn man ein
interaktives Programm von einem anderen aus steuern moechte, weil sich
'manche Dinge', insbesondere, stdio, abhaengig davon, ob sie mit einem
interaktiven Geraet verbunden sind oder nicht, unterschiedlich
verhalten. Ich habe auch selber schon welchen geschrieben. Nichts von
dem, was Du gepostet hast, laesst darauf schliessen, das Du ein
Problem mit Pseudoterminals hast.

Den geposteten Code habe ich mir kurz angesehen und - um das mal ganz
hoeflich auszudruecken - ich denke, dass Deine und meine Vorstellungen
von sinnvollem Software-Design sehr unterschiedlich sind was bereits
bei der Wahl der Programmiersprache anfaengt. Jedenfalls habe ich
keine Lust, das in dieser Form zu debuggen was ich andernfalls
vielleicht getan haette.

Edzard Egberts

unread,
Jan 31, 2012, 11:19:16 AM1/31/12
to
Enrik Berkhan schrieb:
> Edzard Egberts<ed...@tantec.de> wrote:
>> Stimmt, damit ich wenigstens ein paar Kleinigkeiten machen konnte, habe
>> ich den system-Befehl benutzt. Beispiele werde hier aber irgendwie zu
>> eng gesehen, kennst Du den Canon-Capture-Treiber?
>
> Nein, ich kenne _den_ Canon-Capture-Treiber nicht

Eben, das ist genau das interaktive Programm, für dessen Bedienung das
Pseudoterminal ideal wäre, aber ein schlechtes Beispiel, weil den hier
wahrscheinlich niemand kennt. Und ifconfig halte ich für gar kein so
wahnsinnig schlechtes Beispiel, weil man damit nicht nur Parameter
setzen, sondern auch Konfigurationen abfragen kann.

Edzard Egberts

unread,
Jan 31, 2012, 11:42:08 AM1/31/12
to
Rainer Weikusat schrieb:
> Edzard Egberts<ed...@tantec.de> writes:
>> Sehe ich das richtig, dass Du die Unix-Befehle für C/C++-Programme
>> für unbrauchbar hältst und sowieso niemand ein Pseudoterminal
>> verwendet?
>
> Jegliche Form von Netzwerk-Login benutzt notwendigerweise
> Pseudoterminals die (soweit mir das bekannt ist) zu genau diesem
> Zweck irgendwann in den fruehen 1980ern (vermutlich 81, 82 oder 83)
> erfunden wurden. Genaugenommen braucht man die immer, wenn man ein
> interaktives Programm von einem anderen aus steuern moechte, weil
> sich 'manche Dinge', insbesondere, stdio, abhaengig davon, ob sie mit
> einem interaktiven Geraet verbunden sind oder nicht, unterschiedlich
> verhalten.

Na also, das ist genau das was ich will, eigentlich schon läuft und
warum ich jetzt nicht wieder mit irgendwelchen Alternativen herumbasteln
möchte (von denen ich auch schon einige ausprobiert habe). Das wollte
ich doch mal klären. Dank der Zustimmung.

> Nichts von dem, was Du gepostet hast, laesst darauf schliessen, das
> Du ein Problem mit Pseudoterminals hast.

Ich schließe auch eher darauf, dass mein Pseudoterminal ein Problem mit
etwas anderem hat, nur womit?

> Den geposteten Code habe ich mir kurz angesehen und - um das mal
> ganz hoeflich auszudruecken - ich denke, dass Deine und meine
> Vorstellungen von sinnvollem Software-Design sehr unterschiedlich
> sind was bereits bei der Wahl der Programmiersprache anfaengt.

Höflichkeit ist eigentlich nicht meine Stärke und erwarte ich auch nicht
von anderen. Diese spezielle Anwendung könnte ich auch in C schreiben,
aber für den GUI-Krempel, mit dem ich mich sonst herumschlage, halte ich
C++ für bestens geeignet. Alleine die Verwendung der Standardbibliothek
verhindert doch schon Rattennester an Fehlern. Also davon abgesehen -
was stört Dich so?

Meine Vorstellung von sinnvollem Software-Design ist die Header-Klasse -
ein Pseudoterminal ist dazu da, zeilenweise darauf zu schreiben und
davon zu lesen. Keine Ahnung, warum man für so eine Anforderung mehr
machen muss, als ein Objekt zu initialisieren und darauf zu
schreiben/davon zu lesen. Der Code im cpp-Teil ist in meinen Augen
finsterste Steinzeit, da hat man offensichtlich noch nicht mal an
strukturierte Programmierung gedacht, geschweige denn Objekte.

> Jedenfalls habe ich keine Lust, das in dieser Form zu debuggen was
> ich andernfalls vielleicht getan haette.

Das ist nett, aber Du hast gerade noch gesagt, dass ich kein Problem mit
Pseudoterminals habe und der Code ist durchaus funktionsfähig. Ich bin
den auch selber noch ein paar Male durchgegangen und finde keine Stelle,
wo ein Fehler keine Fehlermeldung produzieren würde. Warum funktioniert
Code nicht, der fehlerfrei ausgeführt wird?

Na ja, wenn ich die Brandherde hier ausgetreten habe, gucke ich mir das
bestimmt noch mal an, aber das kam gerade richtig übel...

Enrik Berkhan

unread,
Jan 31, 2012, 12:38:28 PM1/31/12
to
Edzard Egberts <ed...@tantec.de> wrote:
> Eben, das ist genau das interaktive Programm, für dessen Bedienung das
> Pseudoterminal ideal wäre, aber ein schlechtes Beispiel, weil den hier
> wahrscheinlich niemand kennt. Und ifconfig halte ich für gar kein so

Du versuchst ja noch nicht einmal zu erläutern, was das ist.

> wahnsinnig schlechtes Beispiel, weil man damit nicht nur Parameter
> setzen, sondern auch Konfigurationen abfragen kann.

`ifconfig' ist ein sehr schlechtes Beispiel um die Benutzung von
Pseudoterminals zu begründen, denn es Bedarf keinerlei Interaktion oder
Dialogbetriebs.

Aufrufen - Ausgabe lesen - Exit Status Auswerten. Siehe mein Beispiel
mit popen(3).

Pseudoterminals funktionieren natürlich auch einwandfrei, wenn man sie
richtig `bedient'.

Enrik

Edzard Egberts

unread,
Jan 31, 2012, 1:20:08 PM1/31/12
to
Enrik Berkhan schrieb:
> Edzard Egberts<ed...@tantec.de> wrote:
>> Eben, das ist genau das interaktive Programm, für dessen Bedienung das
>> Pseudoterminal ideal wäre, aber ein schlechtes Beispiel, weil den hier
>> wahrscheinlich niemand kennt. Und ifconfig halte ich für gar kein so
>
> Du versuchst ja noch nicht einmal zu erläutern, was das ist.

Ein Kamerainterface. Kann man als Kommandozeile aufrufen oder als
interaktives Programm. Bei letzterem erhält man einen Prompt und kann
Befehle eingeben oder einen Status abfragen, das läßt sich auch pipen.

Aber ins Terminal kommen noch zusätzliche Ausgaben der USB-Schnittstelle
und die lassen sich nicht pipen. Diese Informationen braucht das Gerät
aber. Und es ist ziemlich nervig, wenn man eingeloggt ist und die
Informationen, die man eigentlich im Programm braucht, dauernd aus dem
Nichts auf dem Terminal erscheinen.

> Pseudoterminals funktionieren natürlich auch einwandfrei, wenn man sie
> richtig `bedient'.

Okay, ich glaube dir das. Dann müssen wir auch nicht mehr darüber
diskutieren, dass ich pipen sollte, denn Pseudoterminals sind eine
durchaus elegante, nicht unübliche und bewährte Lösung. Ich müsste nur
den Bug finden. :o)

Rainer Weikusat

unread,
Jan 31, 2012, 1:51:47 PM1/31/12
to
Edzard Egberts <ed...@tantec.de> writes:
>> Edzard Egberts<ed...@tantec.de> writes:
>>> Sehe ich das richtig, dass Du die Unix-Befehle für C/C++-Programme
>>> für unbrauchbar hältst und sowieso niemand ein Pseudoterminal
>>> verwendet?

Mal so als Zwischenbemerkung: Hast Du schon mal ueber die Verwendung
von openpty/ forkpty nachgedacht?

Enrik Berkhan

unread,
Jan 31, 2012, 3:02:48 PM1/31/12
to
Edzard Egberts <ed...@tantec.de> wrote:
> Okay, ich glaube dir das. Dann müssen wir auch nicht mehr darüber
> diskutieren, dass ich pipen sollte, denn Pseudoterminals sind eine
> durchaus elegante, nicht unübliche und bewährte Lösung. Ich müsste nur
> den Bug finden. :o)

Also wenn ich ein Programm "ansteuern" wollte, dessen C Source vorliegt
und ein relativ einfaches Client-Server-System darstellt, dann würde ich
ernsthaft in Erwägung ziehen, dessen main() in client.c an meine
Bedürfnisse anzupassen und den Code einfach zu meinem linken.

Ach herrje, pöse GPL, dann muss man natürlich etwas herumhampeln :)

Aber was habe ich im capture Source übersehen, das ein Pseudoterminal
nötig macht? Die Zeichenkette `tty' kommt jedenfalls im Source nicht
vor.

Gruß,
Enrik

Juergen Ilse

unread,
Jan 31, 2012, 3:20:21 PM1/31/12
to
Hallo,

Edzard Egberts <ed...@tantec.de> wrote:
> Ein Kamerainterface. Kann man als Kommandozeile aufrufen oder als
> interaktives Programm. Bei letzterem erhält man einen Prompt und kann
> Befehle eingeben oder einen Status abfragen, das läßt sich auch pipen.

Wenn es auch mit pipes funktioniert, brauchst du keinpty, weil dann
auch eine pipe genuegt. Wozu benoetigst du da ein pty???

> Aber ins Terminal kommen noch zusätzliche Ausgaben der USB-Schnittstelle
> und die lassen sich nicht pipen.

Warum nicht? Wird da wirklich ein pty benoetigt, oder erfolgen die
Ausgaben lediglich auf stderr (sprich Filehandle 2)? In letzterem
Fall benoetigst du kein pty sondern nur das umlenken von stderr.

> Diese Informationen braucht das Gerät aber. Und es ist ziemlich nervig,
> wenn man eingeloggt ist und die Informationen, die man eigentlich im
> Programm braucht, dauernd aus dem Nichts auf dem Terminal erscheinen.

Das klingt alles danach, als wuerden die Ausgaben nur auf stderr
erfolgen, das bekommt man sogar mit einem shellscript hin, wenn
es denn sein muss. Woher willst du denn wissen, dass du ein pty
benoetigst? Ich wuerde fast drauf wetten, dass du keins brauchst.

Tschuess,
Juergen Ilse (jue...@usenet-verwaltung.de)
--
Ein Domainname ist nur ein Name, nicht mehr und nicht weniger.
Wer mehr hineininterpretiert, hat das Domain-Name-System nicht
verstanden.

Stefan Reuther

unread,
Jan 31, 2012, 3:46:47 PM1/31/12
to
Edzard Egberts wrote:
> Aber ins Terminal kommen noch zusätzliche Ausgaben der USB-Schnittstelle
> und die lassen sich nicht pipen. Diese Informationen braucht das Gerät
> aber. Und es ist ziemlich nervig, wenn man eingeloggt ist und die
> Informationen, die man eigentlich im Programm braucht, dauernd aus dem
> Nichts auf dem Terminal erscheinen.

Sind das auch Meldungen vom Programm, und nicht Meldungen vom Kernel
("new USB device 00:02.0-1, assigned address 2") oder vom von dem
Programm gesteuerten Treiber?

Die fängst du auch mit Pseudoterminals nicht, sondern die landen im Syslog.


Stefan

Rainer Weikusat

unread,
Jan 31, 2012, 5:30:32 PM1/31/12
to
Edzard Egberts <ed...@tantec.de> writes:

[...]

>> Nichts von dem, was Du gepostet hast, laesst darauf schliessen, das
>> Du ein Problem mit Pseudoterminals hast.
>
> Ich schließe auch eher darauf, dass mein Pseudoterminal ein Problem
> mit etwas anderem hat, nur womit?

Ich nehme stark an, dass die shell die Du startest ein Problem mit
'ploetzlichem Rohrbruch' hat (vulgo: Falls das Programm nicht
innerhalb von 0.5s eine Eingabe lesen kann, beendet es sich, und der
naechste Ausgabeversuch dieser shell fuehrt dann zu einem SIGPIPE/
EPIPE). Wahrscheinlich loest folgender (etwas tongue-in-cheek) patch
das Problem:

--- ps/pseudoterminal.cpp 2012-01-31 18:53:14.712519788 +0000
+++ ps.patched//pseudoterminal.cpp 2012-01-31 22:26:27.198669154 +0000
@@ -18,6 +18,7 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
+#include <iostream>

#include "pseudoterminal.h"

@@ -59,6 +60,9 @@ void pseudoterminal::Prompt(string P)
//----------------------------------------------------------------------------
void pseudoterminal::Clear()
{
+ std::cerr << "Trying to read when no input can be available, ignoring\n";
+ return;
+
while (!Read(100).empty()) {} // Pipe leeren
m_Zeile.clear();
}
@@ -98,6 +102,13 @@ string pseudoterminal::Read(int Wait_Mil
fd_set inFds;
FD_ZERO(&inFds);
FD_SET(m_MasterFd, &inFds);
+
+ if (Wait_Millisec != -1)
+ {
+ std::cerr << "misguided use of timeout detected, fixing\n";
+ Wait_Millisec = -1;
+ }
+
if (Wait_Millisec== -1)
{ // Unbegrenzt warten, bis Eingabe von Pseudoterminal eingeht
if (select(m_MasterFd + 1, &inFds, NULL, NULL, 0) == -1)

Edzard Egberts

unread,
Feb 1, 2012, 5:22:21 AM2/1/12
to
Edzard Egberts schrieb:
> 2077 ioctl(0, SNDCTL_TMR_STOP or TCSETSW <unfinished ...>
> 2076 <... write resumed> ) = 37

Was ist das eigentlich für eine "37"? Ich habe das für einen
Rückgabewert gehalten, aber für ioctl() ist dieser Wert gar nicht definiert.

Enrik Berkhan

unread,
Feb 1, 2012, 5:42:12 AM2/1/12
to
Edzard Egberts <ed...@tantec.de> wrote:
> Leider nicht. Was hast Du an der Verwendung von select() auszusetzen?
> Identischer Code für die Verwendung mit Sockets funktioniert auf dem
> gleichen System einwandfrei.
>
> Aber mit dem Vorschlag eines Minimalprogramms hast Du recht:
>
> pseudoterminal PT; // Einstellung des Prompts aus Konstruktor entfernt!
> sleep(2); // Erholungspause nach Erzeugung
> if (PT.Valid()) // Fragt nur interne Variablen ab
> { // Einmalig und direkt Befehl ausgeben:
> PT.Write("echo Hallo Ed > /home/ed/ed_test_txt");
> sleep(10); // 10 s sollten reichen
> }
>
> Die von Dir kritisierten Sachen werden so gar nicht verwendet und ich
> habe es noch einmal mit einem strace versucht. Mit Suche nach write(2,
> "\n" (Zeile 792 im err, Zeile 3066 im ok) kommt man genau auf die
> Stelle, wo etwas schief geht:
>
> 2077 write(2, "\n"..., 1) = 1

Schief gehen tut in beiden Beispielen nichts. Die eine Shell wartet am
Ende deiner 'Eingabe', die andere fängt an, den Befehl abzuarbeiten.

Schick mal ein '\r' als Befehlsabschluss, so wie win Terminal das auch
macht.

Gruß,
Enrik

Enrik Berkhan

unread,
Feb 1, 2012, 6:25:45 AM2/1/12
to
Edzard Egberts <ed...@tantec.de> wrote:
> Edzard Egberts schrieb:
>> 2077 ioctl(0, SNDCTL_TMR_STOP or TCSETSW <unfinished ...>
>> 2076 <... write resumed> ) = 37
^^^^^

Und guck auch mal auf die PID. Alles klar?

Gruß,
Enrik

Enrik Berkhan

unread,
Feb 1, 2012, 6:34:55 AM2/1/12
to
Edzard Egberts <ed...@tantec.de> wrote:
> Stelle, wo etwas schief geht:
>
> 2077 write(2, "\n"..., 1) = 1
> 2077 rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
> 2077 ioctl(0, SNDCTL_TMR_STOP or TCSETSW <unfinished ...>
> 2076 <... write resumed> ) = 37
> 2076 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
> 2076 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
> 2076 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
> 2076 nanosleep({10, 0}, {10, 0}) = 0
>
> Funktionierend sieht das so aus:
>
> 3402 write(2, "\n", 1) = 1
> 3402 rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
> 3402 ioctl(0, SNDCTL_TMR_STOP or SNDRV_TIMER_IOCTL_GINFO or TCSETSW,
> {B38400 opost isig icanon echo ...}) = 0
> 3402 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
> rt_sigaction(SIGTSTP, {SIG_IGN, [], 0}, {SIG_IGN, [], 0}, 8) = 0
> [...]
>
> Da scheint der ioctl()-Aufruf schief zu gehen, sehe ich das richtig?

Ist doch etwas subtiler als in meiner ersten Antwort beschrieben. Der
ioctl() im ersten Beispiel bleibt hängen, anscheinend über 10
Sekunden...

Komisch, aber warum kann ich hier nicht sehen.

Gruß,
Enrik

Edzard Egberts

unread,
Feb 1, 2012, 7:12:20 AM2/1/12
to
Enrik Berkhan schrieb:
> Ist doch etwas subtiler als in meiner ersten Antwort beschrieben. Der
> ioctl() im ersten Beispiel bleibt hängen, anscheinend über 10
> Sekunden...
>
> Komisch, aber warum kann ich hier nicht sehen.

Du meinst aber nicht das hier:

PT.Write("echo Hallo Ed > /home/ed/ed_test_txt");
sleep(10); // 10 s sollten reichen

Rainer meinte, dass das Terminal wahrscheinlich zu schnell geschlossen
wird - so sollte es in jedem Fall genug Zeit haben.
Den nanosleep(10 findest Du auch im zweiten Beispiel, nur passiert
vorher mehr.

Rainer Weikusat

unread,
Feb 1, 2012, 7:16:16 AM2/1/12
to
Edzard Egberts <ed...@tantec.de> writes:
> Rainer Weikusat schrieb:
>> Ich nehme stark an, dass die shell die Du startest ein Problem mit
>> 'ploetzlichem Rohrbruch' hat (vulgo: Falls das Programm nicht
>> innerhalb von 0.5s eine Eingabe lesen kann, beendet es sich, und der
>> naechste Ausgabeversuch dieser shell fuehrt dann zu einem SIGPIPE/
>> EPIPE). Wahrscheinlich loest folgender (etwas tongue-in-cheek) patch
>> das Problem:
>
> Leider nicht. Was hast Du an der Verwendung von select()
> auszusetzen?

Wenn Du ein timeout auf einen zuverlaessigen Datenkanal haben
moechtest, dann musst Du das als Fehler behandeln und die Verbindung
in diesem Fall trennen. Ausserdem ist 'eine halbe Sekunde' oder 'eine
Zehntelsekunde' in jedem Fall viel zu wenig. Sonst gab es nichts
zeitabhaengiges in dem geposteten Code.

[...]


> 2077 write(2, "\n"..., 1) = 1
> 2077 rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
> 2077 ioctl(0, SNDCTL_TMR_STOP or TCSETSW <unfinished ...>
> 2076 <... write resumed> ) = 37
> 2076 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
> 2076 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
> 2076 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
> 2076 nanosleep({10, 0}, {10, 0}) = 0
>
> Funktionierend sieht das so aus:
>
> 3402 write(2, "\n", 1) = 1
> 3402 rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
> 3402 ioctl(0, SNDCTL_TMR_STOP or SNDRV_TIMER_IOCTL_GINFO or TCSETSW,
> {B38400 opost isig icanon echo ...}) = 0
> 3402 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
> rt_sigaction(SIGTSTP, {SIG_IGN, [], 0}, {SIG_IGN, [], 0}, 8) = 0
> [...]
>
> Da scheint der ioctl()-Aufruf schief zu gehen, sehe ich das richtig?

Das sind irgenwelche Systemaufrufe, die die C library aus
irgendwelchen Gruenden macht. Solange sie keinen Fehler an Deinen Code
zurueckmeldet, ist auch nichts schiefgegangen.

Edzard Egberts

unread,
Feb 1, 2012, 7:20:25 AM2/1/12
to
Enrik Berkhan schrieb:
> Schief gehen tut in beiden Beispielen nichts. Die eine Shell wartet am
> Ende deiner 'Eingabe', die andere fängt an, den Befehl abzuarbeiten.
>
> Schick mal ein '\r' als Befehlsabschluss, so wie win Terminal das auch
> macht.

Kein Unterschied, mein Code scheint da zu stimmen:

bool pseudoterminal::Write(string Str)
{
Str+= char(0x0A);
// Ohne Lineend wird der Befehl nicht ausgeführt

Die Shells habe ich übrigens auch schon kontrolliert, $SHELL zeigt auf
eine gültige shell und auch die Alternative ist vorhanden.

Edzard Egberts

unread,
Feb 1, 2012, 7:21:49 AM2/1/12
to
Enrik Berkhan schrieb:
Jetzt ja, diese Zeilennummern kamen mir von Anfang an komisch vor. ;o)

Ansonsten weiß ich nicht so recht, was Dir das sagt...

Edzard Egberts

unread,
Feb 1, 2012, 7:59:17 AM2/1/12
to
Rainer Weikusat schrieb:
>> Leider nicht. Was hast Du an der Verwendung von select()
>> auszusetzen?
>
> Wenn Du ein timeout auf einen zuverlaessigen Datenkanal haben
> moechtest, dann musst Du das als Fehler behandeln und die Verbindung
> in diesem Fall trennen.

Das habe ich immer noch nicht verstanden, der Timeout ist kein Fehler!
Ich habe einen Datenkanal, über den asynchrone Meldungen kommen können
und wenn das Programm nichts zu tun hat, wartet es eine vorgegebene
Zeit, ob etwas kommt. Wenn nicht, weitermachen...
Das ist AFAIK ein Verwendung, für die select() geradezu vorgesehen ist.

> Ausserdem ist 'eine halbe Sekunde' oder 'eine
> Zehntelsekunde' in jedem Fall viel zu wenig.

10 s bringen es auch nicht. Und in einem nicht ganz so verkürztem
Beispiel würde die Software so oft lesen, bis ein Lineend oder der
Prompt erscheint und bis dahin die Teilstücke aufaddieren.

> Das sind irgenwelche Systemaufrufe, die die C library aus
> irgendwelchen Gruenden macht. Solange sie keinen Fehler an Deinen Code
> zurueckmeldet, ist auch nichts schiefgegangen.

Stimmt, der positive Rückgabewert von ioctl() ist tatsächlich kein
Fehler, der wäre -1. Aber ab dieser Stelle fehlt ein ganzer Haufen Code,
eben die Sache mit Datei schreiben.

Okay, es ist also alles fehlerfrei, wird aber nicht ausgeführt, dann
müsste der Befehl doch irgendwo hängen bleiben? Ein fsync() bringt aber
auch nichts, kann man so ein Terminal sonst noch irgendwie triggern?

Edzard Egberts

unread,
Feb 1, 2012, 8:25:51 AM2/1/12
to
Rainer Weikusat schrieb:
> Das sind irgenwelche Systemaufrufe, die die C library aus
> irgendwelchen Gruenden macht. Solange sie keinen Fehler an Deinen Code
> zurueckmeldet, ist auch nichts schiefgegangen.

Aha, ich habe die Fehlermeldung!

errno= 0;
PT.Write("echo Hallo > /home/ed/ed_test_txt");
cout << "PTErr: " << PT.Errno() << " " << PT.Error() << endl;
cout << "Err: " << errno << endl;

Ergibt "PTErr: 0" und "Err: 22". Das heißt, der write-Befehl vom Master
meldet erfolgreiches Schreiben, aber danach geht etwas schief -
"Ungültiger Parameter"? Der Ed nach dem Hallo war es jedenfalls nicht,
dachte, dass da vielleicht das Leerzeichen herumzickt. Warum erscheint
dieser Fehler nicht im strace?

Rainer Weikusat

unread,
Feb 1, 2012, 8:27:18 AM2/1/12
to
Edzard Egberts <ed...@tantec.de> writes:
> Rainer Weikusat schrieb:
>>> Leider nicht. Was hast Du an der Verwendung von select()
>>> auszusetzen?
>>
>> Wenn Du ein timeout auf einen zuverlaessigen Datenkanal haben
>> moechtest, dann musst Du das als Fehler behandeln und die Verbindung
>> in diesem Fall trennen.
>
> Das habe ich immer noch nicht verstanden, der Timeout ist kein
> Fehler!

In Deinem urspruenglichen Beispielprogramm schon: Keine Eingabe fuer
0.5s => Programmende.

[...]

>> Das sind irgenwelche Systemaufrufe, die die C library aus
>> irgendwelchen Gruenden macht. Solange sie keinen Fehler an Deinen Code
>> zurueckmeldet, ist auch nichts schiefgegangen.
>
> Stimmt, der positive Rückgabewert von ioctl() ist tatsächlich kein
> Fehler, der wäre -1.

Und der waere vollkommen egal *ausser* der Aufruf, den Dein Programm
macht, schlaegt fehl.

Rainer Weikusat

unread,
Feb 1, 2012, 8:49:06 AM2/1/12
to
Edzard Egberts <ed...@tantec.de> writes:
> Rainer Weikusat schrieb:
>> Das sind irgenwelche Systemaufrufe, die die C library aus
>> irgendwelchen Gruenden macht. Solange sie keinen Fehler an Deinen Code
>> zurueckmeldet, ist auch nichts schiefgegangen.
>
> Aha, ich habe die Fehlermeldung!
>
> errno= 0;
> PT.Write("echo Hallo > /home/ed/ed_test_txt");
> cout << "PTErr: " << PT.Errno() << " " << PT.Error() << endl;
> cout << "Err: " << errno << endl;
>
> Ergibt "PTErr: 0" und "Err: 22". Das heißt, der write-Befehl vom
> Master meldet erfolgreiches Schreiben, aber danach geht etwas schief -
> "Ungültiger Parameter"?

Der errno-Wert bedeutet nichts *ausser* der C-Library-Aufruf den Du
verwendet hattest hat einen Fehler zurueckgemeldet.

Sieghard Schicktanz

unread,
Feb 1, 2012, 1:05:02 PM2/1/12
to
Hallo Edzard,

Du schriebst am Wed, 01 Feb 2012 13:59:17 +0100:

> Okay, es ist also alles fehlerfrei, wird aber nicht ausgeführt, dann
> müsste der Befehl doch irgendwo hängen bleiben? Ein fsync() bringt aber
> auch nichts, kann man so ein Terminal sonst noch irgendwie triggern?

Vielleicht wartet da doch was / wer auf ein "Enter"? Das ist, wie schon mal
hier gesagt, z.B. ein '\r', und wenn's ein ASCII-Code sein soll, ein 0x0D.
Allerdings _nicht_, wie hier auch zu lesen war, ein 0x0A - _das_ wäre ein
'\n'.

--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------

Enrik Berkhan

unread,
Feb 1, 2012, 3:17:13 PM2/1/12
to
Edzard Egberts <ed...@tantec.de> wrote:
> 2077 write(2, "\n"..., 1) = 1
> 2077 rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
> 2077 ioctl(0, SNDCTL_TMR_STOP or TCSETSW <unfinished ...>
> 2076 <... write resumed> ) = 37
> 2076 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
> 2076 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
> 2076 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
> 2076 nanosleep({10, 0}, {10, 0}) = 0

Scheint ein deadlock zu sein:

aus tty_ioctl(4):

TCSETSW const struct termios *argp
Equivalent to tcsetattr(fd, TCSADRAIN, argp). Allow the output
buffer to drain, and set the current serial port settings.

Die Shell will also warten, bis das Terminal alle Daten abgenommen hat
oder so? Auf der anderen Seite des pty liest aber niemand. Pech :) Wie
sich das im einzelnen verhält, hängt wohl auch von den
Terminaleinstellungen ab (emulieren ptys Handshake?).

Kannst ja mal auf beiden Systemen vergleichen (z.B. mit stty(1)). Beim
Erzeugen des pty kopiert dein Code ja die Einstellungen aus der
aktuellen Sitzung (stdin) auf das pty.

Gruß,
Enrik

Edzard Egberts

unread,
Feb 2, 2012, 2:22:22 AM2/2/12
to
Sieghard Schicktanz schrieb:
> Hallo Edzard,
>
> Du schriebst am Wed, 01 Feb 2012 13:59:17 +0100:
>
>> Okay, es ist also alles fehlerfrei, wird aber nicht ausgeführt, dann
>> müsste der Befehl doch irgendwo hängen bleiben? Ein fsync() bringt aber
>> auch nichts, kann man so ein Terminal sonst noch irgendwie triggern?
>
> Vielleicht wartet da doch was / wer auf ein "Enter"? Das ist, wie schon mal
> hier gesagt, z.B. ein '\r', und wenn's ein ASCII-Code sein soll, ein 0x0D.
> Allerdings _nicht_, wie hier auch zu lesen war, ein 0x0A - _das_ wäre ein
> '\n'.

Das muss ich bezweifeln, 0x0A ist schon richtig '\n' wie Newline.
http://en.wikipedia.org/wiki/Newline

Das deckt sich auch mit meinen Beobachtungen - wenn es funktioniert
(vielleicht sollte ich noch einmal explizit erwähnen, dass der Code
unter Fedora 14 einwandfrei läuft), dann mit 0x0A. Gestern habe ich auch
probiert, was passiert, wenn man \r sendet, gab aber keinen Unterschied.

Edzard Egberts

unread,
Feb 2, 2012, 2:53:21 AM2/2/12
to
Enrik Berkhan schrieb:
> Kannst ja mal auf beiden Systemen vergleichen (z.B. mit stty(1)). Beim
> Erzeugen des pty kopiert dein Code ja die Einstellungen aus der
> aktuellen Sitzung (stdin) auf das pty.

[ed@pc13cms ~]$ stty
speed 38400 baud; line = 0;
eol = M-^?; eol2 = M-^?; swtch = M-^?;
ixany iutf8

root@ccam01000:~# stty
speed 115200 baud; line = 0;
-brkint ixoff -imaxbel

-iexten

Das sieht nach einer heißen Spur aus, unterscheidet sich ja recht
deutlich. Mehr, als mal nebenbei so etwas nachzugucken, ist heute aber
nicht drin. ;o)

Enrik Berkhan

unread,
Feb 2, 2012, 5:13:03 AM2/2/12
to
Edzard Egberts <ed...@tantec.de> wrote:
> Das sieht nach einer heißen Spur aus, unterscheidet sich ja recht
> deutlich. Mehr, als mal nebenbei so etwas nachzugucken, ist heute aber
> nicht drin. ;o)

Dann spendiere dem `stty'-Aufruf beim nächsten mal bitte noch ein `-a'.

Gruß,
Enrik

Edzard Egberts

unread,
Feb 2, 2012, 5:46:25 AM2/2/12
to
Enrik Berkhan schrieb:
Sorry, so weit bin ich in der manpage erst hinterher gekommen: ;o)

root@ccam01000:~# stty -a

speed 115200 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 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

Das könnte es sein: "eol = <undef>" und "eol2 = <undef>"
Ein undefiniertes EndOfLine würde das hängende Terminal erklären.

Rainer Weikusat

unread,
Feb 2, 2012, 11:58:46 AM2/2/12
to
Edzard Egberts <ed...@tantec.de> writes:
> Enrik Berkhan schrieb:
>> Edzard Egberts<ed...@tantec.de> wrote:
>>> Das sieht nach einer heißen Spur aus, unterscheidet sich ja recht
>>> deutlich. Mehr, als mal nebenbei so etwas nachzugucken, ist heute aber
>>> nicht drin. ;o)
>>
>> Dann spendiere dem `stty'-Aufruf beim nächsten mal bitte noch ein `-a'.
>
> Sorry, so weit bin ich in der manpage erst hinterher gekommen: ;o)
>
> root@ccam01000:~# stty -a
>
> speed 115200 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;
>

Genaugenommen koennte alles ein Problem sein, wovon man nichts
versteht. Das da sind sogenannte 'special characters' die vom
Terminaltreiber im Kernel verarbeitet werden und bestimmte Aktionen
ausloesen, zB ^D ein EOF oder ^Z ein suspend. Diese
'Spezialbuchstaben' sind moeglicherweise nicht gesetzt (<undef>).

Mal voellig unabhaengig von den Problem, die Deine zwei dysfunktionale
Beispielprogramme haben oder hatten sowie von saemtlichen Problemen,
die das vollkommen unbekannte Richtige Program[tm] hat oder hatte
solltest Du ein pty, das eine Programm verwendet um eine anderes
Programm zu steuern, dh, das *nicht* mit einem tatsaechlichen
'interaktive Geraet' (zB am anderen Ende einer Netzwerkverbindung)
verbunden ist, in jedem Fall im sogenannten 'rohen Modus' (raw mode)
betreiben, => termios(3).

Sieghard Schicktanz

unread,
Feb 2, 2012, 2:09:13 PM2/2/12
to
Hallo Edzard,

Du schriebst am Thu, 02 Feb 2012 08:22:22 +0100:

> > Vielleicht wartet da doch was / wer auf ein "Enter"? Das ist, wie schon
> > mal hier gesagt, z.B. ein '\r', und wenn's ein ASCII-Code sein soll,
> > ein 0x0D. Allerdings _nicht_, wie hier auch zu lesen war, ein 0x0A -
> > _das_ wäre ein '\n'.

> Das muss ich bezweifeln, 0x0A ist schon richtig '\n' wie Newline.

Daß'n '\n' 0x0A ist, hab' ich ja auch gesagt. 0x0D is'n '\r', ein sog.
"carriage return", auch nur "Return" genannt, wie's die "Enter"-Taste
produziert.

> http://en.wikipedia.org/wiki/Newline

Aber immerhin interessant zu wissen, daß das auch schon zu Wikipedia
durchgdrungen ist. Sogar 'ne eigene Seite für's "newline".

> Das deckt sich auch mit meinen Beobachtungen - wenn es funktioniert
> (vielleicht sollte ich noch einmal explizit erwähnen, dass der Code
> unter Fedora 14 einwandfrei läuft), dann mit 0x0A. Gestern habe ich auch
> probiert, was passiert, wenn man \r sendet, gab aber keinen Unterschied.

Na is doch großartig. Wenn's funktioniert, funktioniert's also sowohl mit
'\n' als auch mit '\r'.
Aber vorsichtshalber haste wohl noch nich probiert, wie's is, wen's nicht
funktioniert?
Ok, ich wer mich da nich weiter einmischen...

Enrik Berkhan

unread,
Feb 2, 2012, 3:59:03 PM2/2/12
to
Sieghard Schicktanz <Sieghard....@schs.de> wrote:
> Na is doch großartig. Wenn's funktioniert, funktioniert's also sowohl mit
> '\n' als auch mit '\r'.

Das liegt am tty-layer, der - wenn nicht z.B. auf `raw' konfiguriert -
per `icrnl' Input setting eine Ersetzung '\r' -> '\n' vornimmt. Das sieht
man auch sehr gut in strace(1) Ausgaben: man sendet '\r' wie ein
richtiges Terminal und die andere Seite empfängt '\n'.

Bei der Ausgabe passiert dann '\n' -> "\r\n", weshalb es keinen
"Treppeneffekt" gibt, so lange `onlcr' gesetzt ist.

Weitere Details s. stty(1) und termios(3).

Gruß,
Enrik

Rainer Weikusat

unread,
Feb 2, 2012, 6:06:36 PM2/2/12
to
Enrik Berkhan <Enrik....@inka.de> writes:
> Edzard Egberts <ed...@tantec.de> wrote:
>> 2077 write(2, "\n"..., 1) = 1
>> 2077 rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
>> 2077 ioctl(0, SNDCTL_TMR_STOP or TCSETSW <unfinished ...>
>> 2076 <... write resumed> ) = 37
>> 2076 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
>> 2076 rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
>> 2076 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
>> 2076 nanosleep({10, 0}, {10, 0}) = 0
>
> Scheint ein deadlock zu sein:

Unter 'deadlock' versteht man eine Situation, bei der n 'unabhaengige
Ausfuehrungseinheiten' keinen weiteren Verarbeitungschritte mehr
durchfuehren koennen weil jeder auf ein lock wartet, welches sich im
Besitz eines anderen befindet. Das liegt hier jedenfalls nicht vor
:-).

Edzard Egberts

unread,
Feb 3, 2012, 2:02:22 AM2/3/12
to
Rainer Weikusat schrieb:
> Edzard Egberts<ed...@tantec.de> writes:
>> Enrik Berkhan schrieb:
>>> Edzard Egberts<ed...@tantec.de> wrote:
>>>> Das sieht nach einer heißen Spur aus, unterscheidet sich ja recht
>>>> deutlich. Mehr, als mal nebenbei so etwas nachzugucken, ist heute aber
>>>> nicht drin. ;o)
>>>
>>> Dann spendiere dem `stty'-Aufruf beim nächsten mal bitte noch ein `-a'.
>>
>> Sorry, so weit bin ich in der manpage erst hinterher gekommen: ;o)
>>
>> root@ccam01000:~# stty -a
>>
>> speed 115200 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;
>>
>
> Genaugenommen koennte alles ein Problem sein, wovon man nichts
> versteht.

Wahre Worte! Lässt sich noch damit steigern, dass man manchmal nicht
einmal weiß, dass man keine Ahnung hat! ;o)
eol und eol2 zu belegen, hat zwar auch noch nichts gebracht, aber da
lassen sich noch stundenlang Optionen setzen...

Edzard Egberts

unread,
Feb 3, 2012, 2:06:55 AM2/3/12
to
Sieghard Schicktanz schrieb:
>> Das deckt sich auch mit meinen Beobachtungen - wenn es funktioniert
>> (vielleicht sollte ich noch einmal explizit erwähnen, dass der Code
>> unter Fedora 14 einwandfrei läuft), dann mit 0x0A. Gestern habe ich auch
>> probiert, was passiert, wenn man \r sendet, gab aber keinen Unterschied.
>
> Na is doch großartig. Wenn's funktioniert, funktioniert's also sowohl mit
> '\n' als auch mit '\r'.
> Aber vorsichtshalber haste wohl noch nich probiert, wie's is, wen's nicht
> funktioniert?

Doch, genau das meinte ich - beim nicht funktionierenden Code macht es
keinen Unterschied, ob man '\n', '\r', "\r\n", "\n\r" sendet.

Rainer Weikusat

unread,
Feb 5, 2012, 4:48:35 PM2/5/12
to
Edzard Egberts <ed...@tantec.de> writes:
> Rainer Weikusat schrieb:
>> Edzard Egberts<ed...@tantec.de> writes:

[...]

>>> root@ccam01000:~# stty -a
>>>
>>> speed 115200 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;
>>>
>>
>> Genaugenommen koennte alles ein Problem sein, wovon man nichts
>> versteht.
>
> Wahre Worte! Lässt sich noch damit steigern, dass man manchmal nicht
> einmal weiß, dass man keine Ahnung hat! ;o)
> eol und eol2 zu belegen, hat zwar auch noch nichts gebracht, aber da
> lassen sich noch stundenlang Optionen setzen...

Ich erlaube mir hier mal ein paar allgemeine Bemerkung zu ptys: Ein
Pseudo-Terminal braucht man normalerweise aus einem von zwei Gruenden,
naemlich entweder moechte man ein Programm, dass stdio benutzt,
fernsteuern und muss es deswegen dazu kriegen, zeilengepuffert und
nicht blockpuffernd zu arbeiten. In diesem Fall sollte man alles, was
der Kernel-Terminaltreiber an Unterstuetzung fuer richtige Terminals
(insofern solche noch irgendwo existieren --- gesehen habe ich seit ca
2001 jedenfalls keins mehr) und interaktive Kommandoeingabe (dh line
editing) und Prozesskontrolle (suspend/ continue) bietet
deaktivieren. Oder man moechte ein interaktives Programm interaktiv
benutzen ohne es direkt via 'terminal' (aka xterm) auszufuehren, zB
ueber ein Netzwerk: In diesem Fall benutzt mein ein 'lokales' Terminal
und dort sollten jegliche Spezialfuntionen deaktiviert sein, damit
alle Ein- und Ausgabe so, wie sie sind an das/ von dem 'entfernte(n)'
Pseudo-Terminal uebertragen werden wobei der Terminaltreiber des
Systems, auf dem das Programm laeuft, fuer line editing etc benutzt
wird.

Gesetzt es handelt sich um den ersten Fall sollte man sich meiner
Ansicht nach lieber nach einer anderen Loesung umsehen denn man wird
das fernzusteuernde Programm 'irgendwie' davon abhalten muessen,
Terminalkontrolloperation durchzufuehren die das fernsteuernde
Program, insofern es keinen eingebauten Terminalemulator hat, nicht
unterstuetzt.

BTW, schon mal an die Moeglichkeit gedacht dass das unterschiedliche
Verhalten die Folge eines sich unterscheiden Satzes von
shell-Initialisierungsskripten, die ausgefuehrt werden weil die Shell
'glaubt', sie sei interaktiv, sein koennte?

Rainer Weikusat

unread,
Feb 6, 2012, 9:56:40 AM2/6/12
to
Rainer Weikusat <rwei...@mssgmbh.com> writes:

[...]

> Ich erlaube mir hier mal ein paar allgemeine Bemerkung zu ptys: Ein
> Pseudo-Terminal braucht man normalerweise aus einem von zwei Gruenden,
> naemlich entweder moechte man ein Programm, dass stdio benutzt,
> fernsteuern und muss es deswegen dazu kriegen, zeilengepuffert und
> nicht blockpuffernd zu arbeiten.

[...]

> man wird das fernzusteuernde Programm 'irgendwie' davon abhalten
> muessen, Terminalkontrolloperation durchzufuehren die das
> fernsteuernde Program, insofern es keinen eingebauten
> Terminalemulator hat, nicht unterstuetzt.

Vorrausgesetzt dass man es nicht mit von irgendwelchen Nachtwaechtern
(zB Robert Landley) entwickelter Weichware zu tun hat, die 'Es ist ein
ANSI-Terminal ! Etwas anderes gibt es nicht !!' in Form von
im Code eingebettenen Escape-Sequenzen fuer ein solches als gegeben
annimmt, sollte man das erreichen koennen, in dem man die
Umgebungsvariable TERM fuer das fernzusteuernde Programm auf dumb
setzt.

0 new messages