Quel processus a créé cette fenêtre X11?

75

Avec un identifiant de fenêtre X11, existe-t-il un moyen de trouver l'identifiant du processus qui l'a créé?

Bien sûr, cela n’est pas toujours possible, par exemple si la fenêtre est passée par une connexion TCP. Dans ce cas, j'aimerais connaître l'adresse IP et le port associés à l'extrémité distante.

La question avait déjà été posée sur le dépassement de pile et une méthode proposée consistait à utiliser la _NET_WM_PIDpropriété. Mais c'est défini par l'application. Y at-il un moyen de le faire si l'application ne joue pas bien?

Gilles, arrête de faire le mal
la source
Connexes: PID de la fenêtre ID / nom
Gilles 'SO- arrête d'être méchant'

Réponses:

60

À moins que votre serveur X prend en charge XResQueryClientIdsde l' extension v1.2 X-ressources Je ne connais pas facile moyen de manière fiable demander l' ID de processus. Il y a d'autres façons cependant.

Si vous avez juste une fenêtre devant vous et que vous ne connaissez pas encore son identifiant, il est facile de le trouver. Ouvrez simplement un terminal à côté de la fenêtre en question, exécutez xwininfo-le et cliquez sur cette fenêtre. xwininfova vous montrer l'id de la fenêtre.

Supposons donc que vous connaissez un identifiant de fenêtre, par exemple 0x1600045, et que vous souhaitiez savoir quel est le processus le possédant.

Le moyen le plus simple de vérifier à qui appartient cette fenêtre est d’exécuter XKillClient, c’est-à-dire:

xkill -id 0x1600045

et voir quel processus vient de mourir. Mais seulement si ça ne vous dérange pas de le tuer bien sûr!

Une autre façon facile , mais peu fiable est de vérifier ses _NET_WM_PIDet WM_CLIENT_MACHINEpropriétés:

xprop -id 0x1600045

C'est ce que les outils aiment xlsclientset xrestopfont.

Malheureusement, ces informations peuvent être incorrectes, non seulement parce que le processus était pervers et les a modifiées, mais également parce qu’il était bogué. Par exemple, après un crash / redémarrage de Firefox, j'ai vu des fenêtres orphelines (provenant du plug-in flash, je suppose) _NET_WM_PIDpointant vers un processus qui s'est éteint depuis longtemps.

Une autre façon est de courir

xwininfo -root -tree

et vérifiez les propriétés des parents de la fenêtre en question. Cela peut aussi vous donner des indices sur l’origine des fenêtres.

Mais! Bien que vous ne trouviez peut-être pas quel processus a créé cette fenêtre, il existe toujours un moyen de savoir où ce processus s'est connecté au serveur X. Et cette façon est pour les vrais hackers. :)

L'identificateur de fenêtre 0x1600045 que vous connaissez avec les bits inférieurs mis à zéro (c.-à-d. 0x1600000) est une "base client". Et tous les ID de ressources alloués à ce client sont "basés" sur celui-ci (0x1600001, 0x1600002, 0x1600003, etc.). X-server stocke des informations sur ses clients dans le groupe de clients [] et, pour chaque client, sa "base" est stockée dans la variable de clients [i] -> clientAsMask. Pour trouver X-socket correspondant à ce client, vous devez vous connecter au serveur X avec gdb, parcourir le tableau clients [], trouver le client avec cela clientAsMasket imprimer son descripteur de socket, stocké dans ((OsCommPtr) (clients [i] - > osPrivate)) -> fd.

Il peut y avoir beaucoup de clients X connectés, donc pour ne pas les vérifier tous manuellement, utilisons une fonction gdb:

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

Lorsque vous trouvez le socket, vous pouvez vérifier qui est connecté et enfin trouver le processus.

AVERTISSEMENT : N'attachez PAS gdb au serveur X depuis INSIDE. gdb suspend le processus auquel il est attaché; ainsi, si vous vous y attachez depuis X-session, vous figez votre serveur X et vous ne pourrez plus interagir avec gdb. Vous devez soit basculer sur text terminal ( Ctrl+Alt+F2), soit vous connecter à votre machine via ssh.

Exemple:

  1. Trouvez le PID de votre serveur X:

    $ 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. L'identifiant de la fenêtre est 0x1600045, la base du client est donc 0x1600000. Attachez au serveur X et recherchez le descripteur de socket client pour cette base de clients. Vous aurez besoin des informations de débogage installées pour le serveur X (paquetage -debuginfo pour les distributions rpm ou paquetage -dbg pour les deb).

    $ 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. Vous savez maintenant que le client est connecté à un socket de serveur 31. Utilisez lsofpour trouver ce qu'est ce socket:

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

    (ici "X" est le nom du processus, "1237" est son pid, "root" est l'utilisateur depuis lequel il est en cours d'exécution, "31u" est un descripteur de socket)

    Là, vous pouvez voir que le client est connecté via TCP, alors vous pouvez aller sur la machine à partir de laquelle il est connecté et vérifier netstat -naple processus. Mais très probablement, vous verrez une prise Unix ici, comme indiqué ci-dessus, ce qui signifie qu'il s'agit d'un client local.

  4. Pour trouver une paire pour ce socket Unix, vous pouvez utiliser la technique de MvG (vous aurez également besoin d'informations de débogage pour votre noyau installé):

    $ sudo gdb -c /proc/kcore
    (gdb) print ((struct unix_sock*)0xffff810008339340)->peer
    $1 = (struct sock *) 0xffff810008339600
    (gdb) quit
    
  5. Maintenant que vous connaissez le socket client, utilisez lsofpour rechercher le PID le tenant:

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

C'est ça. Le processus maintenant cette fenêtre est "firefox" avec l'identifiant de processus 7725


Édition 2017 : Il y a maintenant plus d'options comme on peut le voir sur Qui a l'autre extrémité de cette socket unix? . Avec Linux 3.3 ou supérieur et avec lsof4.89 ou supérieur, vous pouvez remplacer les points 3 à 5 ci-dessus par:

lsof +E -a -p 1237 -d 31

pour savoir qui se trouve à l’autre extrémité du socket sur le disque 31 du processus du serveur X avec l’ID 1237.

Client
la source
6
Bienvenue sur le Unix et Linux Stack Exchange! Votre réponse à cette question est excellente. J'espère que vous reviendrez pour répondre à plus de questions.
36

xdotool n'a pas fonctionné pour moi. Cela a:

Courir

xprop _NET_WM_PID

et cliquez sur la fenêtre.

Ceci est basé sur la réponse à http://www.linuxquestions.org/questions/linux-software-2/advanced-question-finding-pid-of-an-x-window-328983/

Noam
la source
Fonctionne pour moi lorsque la connexion de mon iPhone a déclenché une invite de fenêtre non réactif.
Modulitos
1
Utile pour prouver que, parfois, complètement suspendu. kill $(xprop _NET_WM_PID|cut -d " " -f 3)
Gabriel Devillers
C'est ce que je cherchais, xkill flow
Rombus
13

Si vous avez installé xdotool , alors

xdotool selectwindow getwindowpid

suivi en cliquant sur la fenêtre en question retournera le PID.

(Il existe d'autres moyens de sélectionner la fenêtre en question, par exemple, si vous avez son identifiant de fenêtre, vous pouvez simplement le faire xdotool getwindowpid <number>. Vous pouvez également sélectionner par nom ou par classe, etc.)

Je pense que cela nécessite de jouer gentil de la part du WM. Je n'ai pas beaucoup expérimenté ni eu besoin de le faire.

frabjous
la source
2
xdo_getwinprop(xdo, window, atom_NET_WM_PID, &nitems, &type, &size)⇒ c’est juste un wrapper de shell à lire _NET_WM_PID(utile, mais pas ce que j’ai demandé).
Gilles 'SO- arrête d'être méchant'
11

Le _NET_WM_PIDgestionnaire de fenêtres ne le définit pas (comme un autre client X11, comment le saurait-il?).

Au lieu de cela, les clients X11 conformes (applications) doivent être définis _NET_WM_PIDet WM_CLIENT_MACHINEsur leurs propres fenêtres. En supposant une application bien conçue, cela sera vrai qu'un gestionnaire de fenêtres soit en cours d'exécution ou non.

Si WM_CLIENT_MACHINEest votre propre nom d'hôte, alors le PID devrait être significatif.
Sinon, "je voudrais l'adresse IP et le port associés à l'extrémité distante" - je ne suis pas sûr de ce que cela signifie. Par exemple, si une session ssh est ouverte et que le transfert X est activé, les fenêtres ouvertes par les applications transférées seront marquées avec le PID et le nom d'hôte distants, mais vous n'avez pas nécessairement de moyen de vous reconnecter à cet hôte distant.

éphémère
la source
2
_NET_WM_PIDest défini par l'application: oui, cela a plus de sens! Mais ce n'est pas le protocole X11, c'est la spécification FreeDesktop relativement récente .
Gilles 'SO- arrête d'être méchant'
Dans le cas ssh, en ce qui concerne le serveur X, il s'agit d'une connexion locale issue du processus sshd. Bien que _NET_WM_PIDsemble être défini sur le PID distant et WM_CLIENT_MACHINEsur la connexion à distance (testé avec xterm).
Gilles 'SO- arrête d'être méchant'
4

J'ai pu utiliser la xdotoolversion bêta sous Ubuntu 11.04, mais ce selectwindown'était pas une commande valide, j'ai dû pirater un script avec:

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

puis regardez l’identifiant de la fenêtre défiler pendant que je sélectionnais la fenêtre que je voulais, puis décodait le PID responsable avec:

$ xdotool getwindowpid <the-window-id>
Jon Bailey
la source