Сразу скажу: это как-то реализовано в крупных DE, но я не знаю как и знать не хочу - так что просьба туда не смотреть. Вопрос о том, как должно быть правильно (вне зависимости от того как уже где-то сделано). Возможно, тема не для desktop а для dev, не знаю.
Так вот, простая ситуация - гуи-прога зависла и юзер хочет её завершить. Или не зависла даже, но юзер всё равно хочет её завершить именно аварийным способом. При этом считаем что механизм запуска этой проги тоже у нас в руках, а так же мы можем в умеренных рамках патчить X-server и ядро (хотя лучше без ядра). Но требовать что-то от самой проги свыше дефолтного X11 протокола нельзя (т.е. оно должно работать со всем существующим софтом без патчей).
Проблема разделяется на две: 1) сопоставить окно и pid, 2) найти все побочные pid-ы проги (у неё могут быть подпроцессы) которые тоже надо убить.
Что касается первого, то варианта вижу два:
-
при открывании коннекта к иксам с помощью ядра узнавать кто вызвал connect() на той стороне и запоминать (в линуксе это
getsockopt(SO_PEERCRED)
); -
запускать каждое приложение с отдельным $DISPLAY либо Xauthority, запоминать запущеный pid и где-то хранить таблицу соответствия.
У обоих вариантов есть минус: открыть коннект может один процесс а потом так или иначе отдать сокет другому, иногда совсем другому. В случае первого варианта будет ещё чуть сложнее распознать мультипроцесс приложения. Во втором - схема слишком муторная.
Теперь о втором, варианты такие:
-
запоминать только один pid и с ним и работать
-
считать единым приложением то у чего одинаковый pgid (и обеспечить и его отделение при лаунче)
-
считать единым приложением то у чего одинаковый sid (и обеспечить и его отделение при лаунче)
-
про лаунче засовывать новый процесс в контейнер и определять по контейнеру
Минусы очевидные: первый вариант не учитывает подпроцессы (а надо?), последний - наоборот испортит возможность запустить демон (демона убьют вместе с контейнером), ну а 2-3 плохи тем что их два без чёткой разницы, и есть опасения что их некоторые могут использовать не по назначению.
Чего по-моему делать точно не нужно:
-
искать список с помощью дерева процессов по pid+ppid (стоит кому-то в середине заверщиться как вся ветка его потомков прячется в ppid=1)
-
трассировать всех, ловить
fork()
и запоминать то же дерево но без потерь (слишком накладно и вызовет конфликты с отладчиками).
И ешё вопрос: а надо ли это убивание процесса считать критичным для безопасности действием и старательно затыкать все способы спрятаться от данной системы, или же считать это всего лишь инструментом управления и считать что раз процесс хочет уйти от этого то значит так надо.
Что думаете по поводу всех поднятых вопросов?