Qemu-Monitor - Problem bei Nutzung über Socket

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Hallo zusammen,

derzeit starte ich Qemu über ein Script. Um die VM wieder zu stoppen, möchte ich den Qemu-Monitor über ein Socket nutzen.
Hier der relevante Teil der Qemu-Parameter:

Code: Alles auswählen

-monitor unix:<pfad>,server,nowait
Über "socat" kann ich die VM problemlos stoppen:

Code: Alles auswählen

echo "system_powerdown" | socat - UNIX:<pfad>
Über die Python-Shell funktioniert es auch:

Code: Alles auswählen

>>> import socket
>>> sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
>>> sock.connect(path)
>>> sock.sendall("system_powerdown\n")
>>> sock.close()
>>> 
Wenn ich es allerdings aus einem Script versuche...

Code: Alles auswählen

#!/usr/bin/env python2
import socket
import sys


def send(path):
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    sock.connect(path)
    sock.sendall("system_powerdown\n")
    sock.close()

if __name__ == "__main__":
    if len(sys.argv) > 1:
        send(sys.argv[1])
... passiert nichts ... Keine Fehlermeldung, kein Traceback und die VM läuft weiter ...
(Die Pfade zum Socket stimmen übrigens ...)

Weiss jemand, woran das liegt?
__deets__
User
Beiträge: 14523
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich wuerde ja mal vermuten dein __main__-guard will nicht, aus welchen Gruenden genau kann ich nicht sehen - aber kommentier das doch mal aus, und im Zweifel hard-kodier das argument zu send. Und so tastest du dich an das Problem ran.
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Ich habe das Script etwas geändert:
- Die "if len"-Bedingung rausgenommen
- Den Pfad in "sock.connect" direkt rein geschrieben
- Die Definition und den Aufruf der Funktion angepasst (Parameter fällt ja weg)
- Ein "print" in die Funktion, um sicher zu sein, das sie aufgerufen wird

Keine Änderung am Ergebnis: Keine Fehler und die VM läuft weiter ...
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

Gibt es die print-Ausgabe?
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Ja, die wird angezeigt ...

Ich werde wohl oder übel schauen, das ich den "socat"-Aufruf ins Script nachbaue ... zumindest so lange, bis es in reinem Python geht ...

Könnte es am timing liegen? Ich versuche es mal mit einer kleinen Verzögerung zwischen "sock.connect" und "sock.sendall" ...

[Update]

ein "time.sleep(5)" an der oben erwähnten Stelle brachte keine Änderung ...
(ausser der Verzögerung natürlich)
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

Also wenn es eine Ausgabe gibt und Du zu socket kommst, dann muß es eine Fehlermeldung geben, wenn die selben Befehle in der Shell funktionieren.
Wie rufst Du das Skript auf? root-Rechte?
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Nur als normaler Benutzer ... der socket liegt ja auch in einem Unterordner meines $HOME

Da es in der Python-Shell funktioniert, sollte es doch auch als Funktion in einem eigenen Script funktionieren, oder?

Und bevor jemand fragt: Ich nutze keine IDE, sondern "vim" und "bash" in "xterm" ...
__deets__
User
Beiträge: 14523
Registriert: Mittwoch 14. Oktober 2015, 14:29

hm. wirklich seltsam. socat macht ja nichts anderes als das skript. Kannst du da mal ggf mit strace draufschauen, was da fuer system-calls kommen, und wie die wiederum beim socat aussehen? Wobei du ja auch python in der shell hast, das funktioniert....
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Genau das ist es ja, was ich nicht verstehe ... in der Python-Shell geht es, als eigenständiges Script nicht ...

Ich hab mal die Funktion in einer Python-Shell importiert und aufgerufen ... Es kommen keine Fehlermeldungen ... und die VM läuft weiter ...
__deets__
User
Beiträge: 14523
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das kann nicht sein. Das wird ja langsam magisch. Wie gesagt, versuch mal strace. Oder es ist irgendwas, wo sich die Stirn durch davorklatschen der Hand tief roetet. So wie newline vergessen (ich sehe das hier im Code, aber trotzdem wirklich alles pruefen).
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Da die Datei von "strace" etwas lang ist, pack ich hier mal nur den Schluss rein:

Code: Alles auswählen

sendto(3, "system_powerdown\n", 17, 0, NULL, 0) = 17
close(3)                                = 0
rt_sigaction(SIGINT, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fbb73bf73c0}, {sa_handler=0x7fbb73725cb0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fbb73bf73c0}, 8) = 0
brk(0x557d528bf000)                     = 0x557d528bf000
brk(0x557d528ad000)                     = 0x557d528ad000
munmap(0x7fbb7321c000, 262144)          = 0
exit_group(0)                           = ?
+++ exited with 0 +++
Der Code, den ich im ersten Beitrag rein gestellt hatte ist die Ausgabe von "cat" ...
__deets__
User
Beiträge: 14523
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das sieht ja an sich genau richtig aus - FD 3 sollte der erste freie nach 0,1,2 fuer stdin/out/err sein, und der string der gesandt wird ist auch ok. Wo ist denn der Unterschied zum Interpreter, wenn du das da von hand ausfuehrst? Oder zur Not socat?
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Nachdem ich eine Nacht darüber geschlafen habe:

- Ich weiss nicht, wie "socat" die Kommunikation handhabt
- Der einzige Unterschied zwischen Python-Shell und Script, der mir einfällt ist das timing

Also habe ich das Script vom Anfang um zwei Zeilen bereichert:

Code: Alles auswählen

#!/usr/bin/env python2
import socket
import sys
from time import sleep


def send(path):
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    sock.connect(path)
    sock.sendall("system_powerdown\n")
    sleep(1)
    sock.close()


if __name__ == "__main__":
    if len(sys.argv) > 1:
        send(sys.argv[1])
Also nur ein "sleep(1)" vor dem "sock.close()" ...

Und die VM fährt runter !!!???

Also eigentlich das, was ich erwarte ... nur verstehen tue ich es nicht ...
__deets__
User
Beiträge: 14523
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ah. Hm. Könnte ein seiteneffekt von sendall sein. Oder ein generelles Verhalten, bei dem socat zb mittels select darauf wartet, dass der socket wieder beschreibbar ist, was bedeutet, er Buffert nix mehr.
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@__deets__: das sendall sorgt eigentlich dafür, dass alles gesendet wird.

Was ich mir vorstellen könnte, ist, dass die Gegenseite noch gerne etwas senden würde, es aber nicht kann, weil der Socket schon wieder geschlossen ist.
Dann müßte ein recv helfen:

Code: Alles auswählen

def send(path, command="system_powerdown"):
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    sock.connect(path)
    sock.sendall(command + "\n")
    print(sock.recv(100))
    sock.close()
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Hab ich mal ausprobiert ... selbst wenn ich ein "print sock.recv(1000)" einbaue bringt es nichts ...
__deets__
User
Beiträge: 14523
Registriert: Mittwoch 14. Oktober 2015, 14:29

Der socat-code ist ziemlich komplex. Auch da wuerde wahrscheinlich strace helfen um zu sehen, was die mit dem fd machen, nachdem das Kommando durchkam.
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Hab mal "socat" mit "strace" laufen lassen:

Code: Alles auswählen

recvfrom(3, 0x7ffc0239a8e0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
getsockname(5, {sa_family=AF_UNIX}, [112->2]) = 0
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
select(6, [0 5], [1 5], [], NULL)       = 3 (in [5], out [1 5])
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
recvfrom(3, 0x7ffc0239a7a0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
read(5, "QEMU 3.0.0 monitor - type 'help'"..., 8192) = 62
recvfrom(3, 0x7ffc0239a7a0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
recvfrom(3, 0x7ffc0239aca0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
write(1, "QEMU 3.0.0 monitor - type 'help'"..., 62) = 62
recvfrom(3, 0x7ffc0239aca0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
select(6, [0 5], [1], [], NULL)         = 1 (out [1])
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
select(6, [0 5], [], [], NULL)          = 1 (in [0])
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
recvfrom(3, 0x7ffc0239a7a0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
read(0, "system_powerdown\n", 8192)     = 17
recvfrom(3, 0x7ffc0239a7a0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
recvfrom(3, 0x7ffc0239aca0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
write(5, "system_powerdown\n", 17)      = 17
recvfrom(3, 0x7ffc0239aca0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
select(6, [0 5], [5], [], NULL)         = 2 (in [5], out [5])
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
recvfrom(3, 0x7ffc0239a7a0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
read(5, "s\33[K\33[Dsy\33[K\33[D\33[Dsys\33[K\33[D\33[D\33["..., 8192) = 480
recvfrom(3, 0x7ffc0239a7a0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
recvfrom(3, 0x7ffc0239aca0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
write(1, "s\33[K\33[Dsy\33[K\33[D\33[Dsys\33[K\33[D\33[D\33["..., 480) = 480
recvfrom(3, 0x7ffc0239aca0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
select(6, [0 5], [1], [], NULL)         = 2 (in [5], out [1])
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
recvfrom(3, 0x7ffc0239a7a0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
read(5, "\33[D\33[D\33[D\33[D\33[D\33[D\33[D\33[D\33[D\33[D\33["..., 8192) = 73
recvfrom(3, 0x7ffc0239a7a0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
recvfrom(3, 0x7ffc0239aca0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
write(1, "\33[D\33[D\33[D\33[D\33[D\33[D\33[D\33[D\33[D\33[D\33["..., 73) = 73
recvfrom(3, 0x7ffc0239aca0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
select(6, [0 5], [1], [], NULL)         = 1 (out [1])
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
select(6, [0 5], [], [], NULL)          = 1 (in [0])
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
recvfrom(3, 0x7ffc0239a7a0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
read(0, "", 8192)                       = 0
recvfrom(3, 0x7ffc0239a7a0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
shutdown(5, SHUT_WR)                    = 0
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
select(6, [5], [], [], {tv_sec=0, tv_usec=500000}) = 0 (Timeout)
recvfrom(3, 0x7ffc0239ad10, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
ioctl(0, SNDCTL_TMR_START or TCSETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, SNDCTL_TMR_START or TCSETS, {B38400 opost isig icanon echo ...}) = 0
shutdown(5, SHUT_RDWR)                  = 0
recvfrom(3, 0x7ffc0239aff0, 519, MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Die Ressource ist zur Zeit nicht verfügbar)
exit_group(0)                           = ?
+++ exited with 0 +++
__deets__
User
Beiträge: 14523
Registriert: Mittwoch 14. Oktober 2015, 14:29

Also der macht definitiv ein select, und danach ein read. Hast du auch das select gemacht? Wobei ich die Daten, die er dann wirklich liest komisch finde.
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Wie müsste ich die Funktion ändern, um da ein "select" einzubauen?
Wobei ich ehrlich zugebe, das die ganze Netzwerk-Programmierung für mich Neuland ist ...
Antworten