Welcher Prozess hat dieses X11-Fenster erstellt?


75

Gibt es bei einer X11-Fenster-ID eine Möglichkeit, die ID des Prozesses zu ermitteln, der sie erstellt hat?

Dies ist natürlich nicht immer möglich, zum Beispiel wenn das Fenster über eine TCP-Verbindung kam. Für diesen Fall möchte ich die IP und den Port, die mit dem entfernten Ende verbunden sind.

Die Frage wurde zuvor zu Stack Overflow gestellt , und es wurde vorgeschlagen, die _NET_WM_PIDEigenschaft zu verwenden. Aber das wird von der Anwendung festgelegt. Gibt es eine Möglichkeit, dies zu tun, wenn die Anwendung nicht gut abgespielt wird?


Antworten:


60

Es sei denn , Ihr X-Server unterstützt XResQueryClientIdsvon v1.2 Erweiterung X-Ressource weiß , dass ich keine einfache Art und Weise zu zuverlässig Prozess - ID anfordern. Es gibt jedoch auch andere Möglichkeiten.

Wenn Sie nur ein Fenster vor sich haben und dessen ID noch nicht kennen, können Sie es leicht herausfinden. Öffnen Sie einfach ein Terminal neben dem betreffenden Fenster, führen Sie xwininfoes aus und klicken Sie auf dieses Fenster. xwininfozeigt Ihnen die Fenster-ID.

Nehmen wir also an, Sie kennen eine Fenster-ID, z. B. 0x1600045, und möchten herausfinden, in welchem ​​Prozess sie sich befindet.

Am einfachsten können Sie überprüfen, wem dieses Fenster gehört, indem Sie XKillClient für dieses Fenster ausführen.

xkill -id 0x1600045

und sehen, welcher Prozess gerade gestorben ist. Aber nur, wenn Sie nichts dagegen haben, es natürlich zu töten!

Eine weitere einfache aber unzuverlässig Art und Weise ist die zu überprüfen _NET_WM_PIDund WM_CLIENT_MACHINEEigenschaften:

xprop -id 0x1600045

Das ist, was Werkzeuge mögen xlsclientsund xrestoptun.

Leider können diese Informationen nicht nur falsch sein, weil der Prozess schlecht war und diese geändert hat, sondern auch, weil er fehlerhaft war. Zum Beispiel habe ich nach einem Firefox-Absturz / Neustart verwaiste Fenster (vom Flash-Plugin, denke ich) mit einem _NET_WM_PIDHinweis auf einen Prozess gesehen, der vor langer Zeit gestorben ist.

Alternative Weg ist zu laufen

xwininfo -root -tree

und überprüfen Sie die Eigenschaften der Eltern des betreffenden Fensters. Das kann Ihnen auch Hinweise auf die Fensterherkunft geben.

Aber! Sie können möglicherweise nicht feststellen, von welchem ​​Prozess dieses Fenster erstellt wurde, aber es gibt immer noch eine Möglichkeit, festzustellen, von wo aus dieser Prozess eine Verbindung zum X-Server hergestellt hat. Und so ist es für echte Hacker. :)

Die Windows-ID 0x1600045, die Sie kennen, wenn niedrigere Bits auf Null gesetzt sind (dh 0x1600000), ist eine "Client-Basis". Alle für diesen Client zugewiesenen Ressourcen-IDs basieren darauf (0x1600001, 0x1600002, 0x1600003 usw.). X-Server speichert Informationen zu seinen Clients im clients [] -Array und für jeden Client wird seine "Basis" in der clientAsMask-Variablen [i] -> gespeichert. Um den X-Socket zu finden, der diesem Client entspricht, müssen Sie eine Verbindung zum X-Server mit dem gdbArray clients [] herstellen, den Client damit suchen clientAsMaskund dessen Socket-Deskriptor ausgeben, der in ((OsCommPtr) (clients [i] - > osPrivate)) -> fd.

Möglicherweise sind viele X-Clients verbunden. Um sie also nicht alle manuell zu überprüfen, verwenden wir eine GDB-Funktion:

define findclient
  set $ii = 0
  while ($ii < currentMaxClients)
    if (clients[$ii] != 0 && clients[$ii]->clientAsMask == $arg0 && clients[$ii]->osPrivate != 0)
      print ((OsCommPtr)(clients[$ii]->osPrivate))->fd
    end
    set $ii = $ii + 1
  end
end

Wenn Sie den Socket gefunden haben, können Sie überprüfen, wer mit ihm verbunden ist, und schließlich den Prozess finden.

WARNUNG : Schließen Sie KEINE GDB von INNERHALB des X-Servers an den X-Server an. gdb unterbricht den Prozess, mit dem es verbunden ist. Wenn Sie also innerhalb von X-session eine Verbindung herstellen, frieren Sie Ihren X-Server ein und können nicht mehr mit gdb interagieren. Sie müssen entweder zum Textterminal ( Ctrl+Alt+F2) wechseln oder über ssh eine Verbindung zu Ihrem Computer herstellen.

Beispiel:

  1. Finden Sie die PID Ihres X-Servers:

    $ ps ax | grep X
     1237 tty1     Ssl+  11:36 /usr/bin/X :0 vt1 -nr -nolisten tcp -auth /var/run/kdm/A:0-h6syCa
    
  2. Die Fenster-ID lautet 0x1600045, die Client-Basis also 0x1600000. Stellen Sie eine Verbindung zum X-Server her und suchen Sie den Client-Socket-Deskriptor für diese Client-Basis. Sie müssen Debug-Informationen für X-Server installiert haben (-debuginfo-Paket für rpm-Distributionen oder -dbg-Paket für debs).

    $ sudo gdb
    (gdb) define findclient
    Type commands for definition of "findclient".
    End with a line saying just "end".
    >  set $ii = 0
    >  while ($ii < currentMaxClients)
     >   if (clients[$ii] != 0 && clients[$ii]->clientAsMask == $arg0 && clients[$ii]->osPrivate != 0)
      >     print ((OsCommPtr)(clients[$ii]->osPrivate))->fd
      >     end
     >   set $ii = $ii + 1
     >   end
    >  end
    (gdb) attach 1237
    (gdb) findclient 0x1600000
    $1 = 31
    (gdb) detach
    (gdb) quit
    
  3. Jetzt wissen Sie, dass der Client mit einem Server-Socket 31 verbunden lsofist.

    $ sudo lsof -n | grep 1237 | grep 31
    X        1237    root   31u   unix 0xffff810008339340       8512422 socket
    

    (hier ist "X" der Prozessname, "1237" die PID, "root" der Benutzer, von dem aus er ausgeführt wird, "31u" ist ein Socket-Deskriptor)

    Dort sehen Sie möglicherweise, dass der Client über TCP verbunden ist, und können dann zu dem Computer gehen, von dem aus die Verbindung hergestellt wurde, und netstat -napdort nach dem Prozess suchen. Aber höchstwahrscheinlich sehen Sie dort einen Unix-Socket, wie oben gezeigt, was bedeutet, dass es sich um einen lokalen Client handelt.

  4. Um ein Paar für diesen Unix-Socket zu finden, können Sie die MvG-Technik verwenden (Sie benötigen auch Debug-Informationen für Ihren installierten Kernel):

    $ sudo gdb -c /proc/kcore
    (gdb) print ((struct unix_sock*)0xffff810008339340)->peer
    $1 = (struct sock *) 0xffff810008339600
    (gdb) quit
    
  5. Nun, da Sie den Client-Socket kennen, können lsofSie die PID ermitteln, in der sich der Socket befindet :

    $ sudo lsof -n | grep 0xffff810008339600
    firefox  7725  username  146u   unix 0xffff810008339600       8512421 socket
    

Das ist es. Der Prozess, der dieses Fenster beibehält, ist "Firefox" mit der Prozess-ID 7725


2017 Edit : Es gibt jetzt mehr Optionen, wie unter Wer hat das andere Ende dieses Unix-Socketpaars? . Ab Linux 3.3 und lsof4.89 können Sie die obigen Punkte 3 bis 5 ersetzen durch:

lsof +E -a -p 1237 -d 31

um herauszufinden, wer sich am anderen Ende des Sockets auf fd 31 des X-Server-Prozesses mit der ID 1237 befindet.


6
Willkommen beim Unix und Linux Stack Exchange! Ihre Antwort auf diese Frage ist ausgezeichnet. Ich hoffe, Sie kommen zurück, um weitere Fragen zu beantworten.

36

xdotool hat bei mir nicht funktioniert. Dies tat:

Lauf

xprop _NET_WM_PID

und klicke auf das Fenster.

Dies basiert auf der Antwort unter http://www.linuxquestions.org/questions/linux-software-2/advanced-question-finding-pid-of-an-x-window-328983/


Funktioniert für mich, wenn ich mein Iphone einstecke und eine nicht reagierende Fenster-Eingabeaufforderung erhalte.
Modulitos

1
Nützlich für den Beweis, dass das manchmal komplett hing. kill $(xprop _NET_WM_PID|cut -d " " -f 3)
Gabriel Devillers

Dies ist, wonach ich gesucht habe, xkill flow
Rombus

13

Wenn Sie xdotool installiert haben, dann

xdotool selectwindow getwindowpid

gefolgt von einem Klick auf das betreffende Fenster wird die PID zurückgegeben.

(Sie können das betreffende Fenster auch auf andere Weise auswählen, z. B. wenn Sie über die entsprechende Fenster-ID verfügen xdotool getwindowpid <number>. Sie können die Auswahl auch nach Name oder Klasse usw. vornehmen.)

Ich denke, das erfordert ein nettes Spiel im Namen der WM. Ich habe nicht viel experimentiert oder musste.


2
xdo_getwinprop(xdo, window, atom_NET_WM_PID, &nitems, &type, &size)⇒ Es ist nur ein Shell-Wrapper zum Lesen _NET_WM_PID(nützlich, aber nicht das, wonach ich gefragt habe).
Gilles

11

Das _NET_WM_PIDwird nicht vom Fenstermanager festgelegt (wie nur ein anderer X11-Client, wie würde es wissen?).

Stattdessen müssen kompatible X11-Clients (Anwendungen) _NET_WM_PIDund WM_CLIENT_MACHINEin ihren eigenen Fenstern eingerichtet werden. Vorausgesetzt, dass sich eine Anwendung gut verhält, ist dies der Fall, unabhängig davon, ob ein Fenstermanager ausgeführt wird oder nicht.

Wenn WM_CLIENT_MACHINEes sich um Ihren eigenen Hostnamen handelt, sollte die PID aussagekräftig sein.
Andernfalls "Ich möchte die IP und den Port, die mit dem Remote-Ende verknüpft sind" - ich bin mir nicht sicher, was das bedeutet. Wenn Sie beispielsweise eine SSH-Sitzung mit aktivierter X-Weiterleitung geöffnet haben, werden Fenster, die von weitergeleiteten Apps geöffnet werden, mit der Remote-PID und dem Hostnamen gekennzeichnet. Sie haben jedoch nicht unbedingt die Möglichkeit, eine Verbindung zu diesem Remote-Host herzustellen.


2
_NET_WM_PIDwird von der anwendung gesetzt: richtig, das macht mehr sinn! Es ist jedoch nicht das X11-Protokoll, sondern die relativ aktuelle FreeDesktop- Spezifikation.
Gilles

Im ssh-Fall handelt es sich für den X-Server um eine lokale Verbindung vom sshd-Prozess. Scheint allerdings _NET_WM_PIDauf die Remote-PID und WM_CLIENT_MACHINEauf die Remote-Verbindung eingestellt zu sein (getestet mit xterm).
Gilles

4

Ich konnte das xdotoolunter Ubuntu 11.04 Beta benutzen , war aber selectwindowkein gültiger Befehl, ich musste ein Skript hacken mit:

$ while true; do sleep 1; xdotool getactivewindow; done

Beobachten Sie dann, wie die Fenster-ID vergeht, während ich das gewünschte Fenster auswählte, und decodieren Sie dann die verantwortliche PID mit:

$ xdotool getwindowpid <the-window-id>
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.