กระบวนการใดที่สร้างหน้าต่าง X11 นี้


75

รับ ID หน้าต่าง X11 มีวิธีหา ID ของกระบวนการที่สร้างมันขึ้นมาหรือไม่?

แน่นอนว่ามันเป็นไปไม่ได้เสมอไปเช่นถ้าหน้าต่างมาผ่านการเชื่อมต่อ TCP สำหรับกรณีนี้ฉันต้องการ IP และพอร์ตที่เกี่ยวข้องกับ remote end

คำถามที่ถูกถามก่อนใน Stack Overflowและวิธีการที่เสนอคือการใช้_NET_WM_PIDคุณสมบัติ แต่นั่นถูกกำหนดโดยแอปพลิเคชัน มีวิธีทำอย่างไรหากแอปพลิเคชันเล่นได้ไม่ดี?


คำตอบ:


60

เว้นแต่ X-เซิร์ฟเวอร์ของคุณสนับสนุนXResQueryClientIdsจากการขยาย v1.2 X-ทรัพยากรฉันรู้ว่าไม่ง่ายวิธีที่จะเชื่อถือได้ขอหมายเลขกระบวนการ มีวิธีอื่น ๆ

หากคุณมีหน้าต่างอยู่ข้างหน้าคุณและยังไม่ทราบ ID มันเป็นเรื่องง่ายที่จะค้นหา เพียงเปิดเทอร์มินัลถัดจากหน้าต่างที่มีปัญหาเรียกใช้ที่xwininfoนั่นและคลิกที่หน้าต่างนั้น xwininfoจะแสดง window-id ให้คุณ

ดังนั้นสมมติว่าคุณรู้จัก window-id เช่น 0x1600045 และต้องการค้นหาสิ่งที่กระบวนการเป็นเจ้าของ

วิธีที่ง่ายที่สุดในการตรวจสอบว่าใครเป็นเจ้าของหน้าต่างนั้นก็คือเรียกใช้ XKillClient เช่น:

xkill -id 0x1600045

และดูว่ากระบวนการใดเพิ่งเสียชีวิต แต่ถ้าคุณไม่รังเกียจที่จะฆ่ามันแน่นอน!

อีกวิธีที่ง่าย แต่ไม่น่าเชื่อถือคือการตรวจสอบ_NET_WM_PIDและWM_CLIENT_MACHINEคุณสมบัติ:

xprop -id 0x1600045

นั่นคือสิ่งที่เครื่องมือชอบxlsclientsและxrestopทำ

น่าเสียดายที่ข้อมูลนี้อาจไม่ถูกต้องไม่เพียงเพราะกระบวนการนี้เป็นสิ่งที่ชั่วร้ายและเปลี่ยนแปลงสิ่งเหล่านั้น แต่ยังเป็นเพราะมันเป็นรถ เช่นหลังจาก firefox crash / restart ฉันเห็น windows กำพร้า (จาก flash plugin ฉันเดา) ด้วยการ_NET_WM_PIDชี้ไปที่กระบวนการซึ่งเสียชีวิตไปนานแล้ว

ทางเลือกคือการวิ่ง

xwininfo -root -tree

และตรวจสอบคุณสมบัติของผู้ปกครองของหน้าต่างที่เป็นปัญหา ที่อาจให้คำแนะนำบางอย่างเกี่ยวกับต้นกำเนิดของหน้าต่าง

แต่! แม้ว่าคุณอาจไม่พบว่ากระบวนการใดสร้างหน้าต่างนั้น แต่ก็ยังมีวิธีการค้นหาว่ากระบวนการนั้นเชื่อมต่อกับ X-server จากที่ไหน และนั่นก็คือแฮกเกอร์ตัวจริง :)

window-id 0x1600045 ที่คุณรู้ว่ามีบิตต่ำกว่าเป็นศูนย์ (เช่น 0x1600000) คือ "ฐานลูกค้า" และ ID ทรัพยากรทั้งหมดที่ปันส่วนสำหรับไคลเอนต์นั้น "อิง" (0x1600001, 0x1600002, 0x1600003, ฯลฯ ) X-server เก็บข้อมูลเกี่ยวกับลูกค้าในอาร์เรย์ [] และสำหรับลูกค้าแต่ละรายนั้น "ฐาน" จะถูกเก็บไว้ในไคลเอนต์ [i] -> ตัวแปร clientAsMask ในการค้นหา X-socket ที่สอดคล้องกับไคลเอนต์นั้นคุณต้องแนบไปกับ X-server ด้วยgdb, เดินไปที่อาร์เรย์ของลูกค้า [], ค้นหาไคลเอ็นต์ด้วยนั้นclientAsMaskและพิมพ์ตัวอธิบายซ็อกเก็ตของมันซึ่งเก็บอยู่ใน ((OsCommPtr) (clients [i] - > osPrivate)) -> FD

อาจมีการเชื่อมต่อไคลเอนต์ X จำนวนมากดังนั้นเพื่อที่จะไม่ตรวจสอบพวกเขาทั้งหมดด้วยตนเองลองใช้ฟังก์ชั่น 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

เมื่อคุณพบซ็อกเก็ตคุณสามารถตรวจสอบผู้ที่เชื่อมต่อกับมันและในที่สุดก็พบกระบวนการ

คำเตือน : อย่าแนบ gdb กับ X-server จากภายใน X-server gdb ระงับกระบวนการที่แนบไว้ดังนั้นหากคุณแนบจากภายใน X-session คุณจะตรึง X-server ของคุณและจะไม่สามารถโต้ตอบกับ gdb ได้ คุณต้องสลับไปที่เทอร์มินัลข้อความ ( Ctrl+Alt+F2) หรือเชื่อมต่อกับเครื่องของคุณผ่าน ssh

ตัวอย่าง:

  1. ค้นหา PID ของ X-server ของคุณ:

    $ 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. รหัสหน้าต่างคือ 0x1600045 ดังนั้นฐานลูกค้าคือ 0x16000000 แนบไปกับ X-server และค้นหาตัวบอกซ็อกเก็ตไคลเอ็นต์สำหรับฐานลูกค้านั้น คุณจะต้องติดตั้งข้อมูล debug สำหรับ X-server (-debuginfo แพ็คเกจสำหรับ rpm-distributions หรือ -dbg package สำหรับ deb's)

    $ 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. ตอนนี้คุณรู้ว่าไคลเอ็นต์เชื่อมต่อกับเซิร์ฟเวอร์ซ็อกเก็ต 31 ใช้lsofเพื่อค้นหาว่าซ็อกเก็ตนั้นคืออะไร:

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

    (ที่นี่ "X" เป็นชื่อกระบวนการ "1237" เป็น pid "root" เป็นผู้ใช้ที่ทำงานอยู่ "31u" เป็นตัวบ่งชี้ซ็อกเก็ต)

    ที่นั่นคุณอาจเห็นว่าไคลเอนต์เชื่อมต่อผ่าน TCP จากนั้นคุณสามารถไปที่เครื่องที่เชื่อมต่อจากนั้นและตรวจสอบที่netstat -napนั่นเพื่อค้นหากระบวนการ แต่ส่วนใหญ่คุณจะเห็นซ็อกเก็ตยูนิกซ์ที่นั่นดังที่แสดงไว้ด้านบนซึ่งหมายความว่าเป็นลูกค้าในพื้นที่

  4. ในการค้นหาคู่สำหรับซ็อกเก็ตยูนิกซ์นั้นคุณสามารถใช้เทคนิคของ MvG (คุณจะต้องใช้ข้อมูลการดีบักสำหรับเคอร์เนลที่ติดตั้งด้วย):

    $ sudo gdb -c /proc/kcore
    (gdb) print ((struct unix_sock*)0xffff810008339340)->peer
    $1 = (struct sock *) 0xffff810008339600
    (gdb) quit
    
  5. ตอนนี้คุณรู้ซ็อกเก็ตไคลเอ็นต์แล้วใช้lsofเพื่อค้นหา PID ที่ถือมัน:

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

แค่นั้นแหละ. กระบวนการที่ทำให้หน้าต่างนั้นเป็น "firefox" ด้วย process-id 7725


2017 แก้ไข : มีตัวเลือกเพิ่มเติมตามที่เห็นในตอนนี้ใครบ้างที่มีจุดสิ้นสุดของซ็อกเก็ตยูนิกซ์นี้? . ด้วย Linux 3.3 หรือสูงกว่าและด้วยlsof4.89 หรือสูงกว่าคุณสามารถแทนที่คะแนน 3 ถึง 5 ด้านบนด้วย:

lsof +E -a -p 1237 -d 31

เพื่อค้นหาว่าใครอยู่ที่ปลายอีกด้านของซ็อกเก็ตบน fd 31 ของกระบวนการ X-server ด้วย ID 1237


6
ยินดีต้อนรับ Unix และ Linux Stack Exchange! คำตอบของคุณสำหรับคำถามนี้ยอดเยี่ยม ฉันหวังว่าคุณจะกลับมาตอบคำถามเพิ่มเติม

36

xdotool ไม่ได้ผลสำหรับฉัน สิ่งนี้ทำ:

วิ่ง

xprop _NET_WM_PID

และคลิกที่หน้าต่าง

นี้จะขึ้นอยู่กับคำตอบที่http://www.linuxquestions.org/questions/linux-software-2/advanced-question-finding-pid-of-an-x-window-328983/


เหมาะกับฉันเมื่อเสียบ iPhone ของฉันแสดงหน้าต่างแจ้งเตือนที่ไม่ตอบสนอง
modulitos

1
มีประโยชน์สำหรับ evince ที่แขวนบางครั้งอย่างสมบูรณ์ kill $(xprop _NET_WM_PID|cut -d " " -f 3)
Gabriel Devillers

นี่คือสิ่งที่ฉันกำลังมองหา xkill flow
Rombus

13

หากคุณติดตั้งxdotoolไว้

xdotool selectwindow getwindowpid

ตามด้วยการคลิกที่หน้าต่างดังกล่าวจะส่งคืน PID

(มีวิธีอื่นในการเลือกหน้าต่างที่เป็นปัญหาเช่นหากคุณมี ID หน้าต่างคุณสามารถทำได้xdotool getwindowpid <number>คุณสามารถเลือกตามชื่อหรือคลาสเป็นต้น)

ฉันคิดว่านี่ต้องมีการเล่นที่ดีในนามของ WM ฉันไม่ได้ทดลองมากหรือต้องการ


2
xdo_getwinprop(xdo, window, atom_NET_WM_PID, &nitems, &type, &size)⇒เป็นเพียงเครื่องห่อหุ้มเปลือกเพื่ออ่าน_NET_WM_PID(มีประโยชน์ แต่ไม่ใช่สิ่งที่ฉันขอ)
Gilles

11

ตัว_NET_WM_PIDจัดการหน้าต่างไม่ได้ถูกตั้งค่า (เช่นเดียวกับไคลเอนต์ X11 อีกคนจะรู้ได้อย่างไร)

แต่จะต้องตั้งค่าไคลเอนต์ X11 (แอปพลิเคชั่น) ที่เป็นไปตามมาตรฐาน_NET_WM_PIDและWM_CLIENT_MACHINEบนหน้าต่างของตนเอง สมมติว่าแอปพลิเคชันที่ทำงานได้ดีนี่จะเป็นจริงว่าตัวจัดการหน้าต่างกำลังทำงานอยู่หรือไม่

หากWM_CLIENT_MACHINEเป็นชื่อโฮสต์ของคุณเอง PID ควรมีความหมาย
มิฉะนั้น "ฉันต้องการ IP และพอร์ตที่เกี่ยวข้องกับการสิ้นสุดระยะไกล" - ฉันไม่แน่ใจว่ามันหมายถึงอะไร ตัวอย่างเช่นหากคุณเปิดเซสชัน ssh โดยเปิดใช้งานการส่งต่อ X หน้าต่างที่เปิดโดยแอปที่ส่งต่อจะถูกทำเครื่องหมายด้วย PID ระยะไกลและชื่อโฮสต์ แต่คุณไม่จำเป็นต้องเชื่อมต่อกลับไปยังโฮสต์ระยะไกลนั้น


2
_NET_WM_PIDถูกตั้งค่าโดยแอปพลิเคชัน: ใช่แล้วมันสมเหตุสมผลดีกว่า แต่มันไม่ได้เป็นโปรโตคอล X11 ก็ล่าสุดค่อนข้างfreedesktopสเปค
Gilles

ในกรณี ssh เท่าที่เกี่ยวข้องกับเซิร์ฟเวอร์ X นี่คือการเชื่อมต่อภายในเครื่องจากกระบวนการ sshd แม้ว่า_NET_WM_PIDดูเหมือนว่าจะถูกตั้งค่าเป็น PID ระยะไกลและWM_CLIENT_MACHINEการเชื่อมต่อระยะไกล (ทดสอบด้วย xterm)
Gilles

4

ฉันสามารถใช้งานxdotoolUbuntu 11.04 เบต้าภายใต้ แต่selectwindowไม่ใช่คำสั่งที่ถูกต้องฉันต้องแฮกสคริปต์ด้วย:

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

จากนั้นดู ID หน้าต่างที่ผ่านไปในขณะที่ฉันเลือกหน้าต่างที่ฉันต้องการจากนั้นถอดรหัส PID ที่รับผิดชอบด้วย:

$ xdotool getwindowpid <the-window-id>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.