From 2dd43bba016420212b80f6d5cc4c97dc8f7e497c Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Mon, 9 Mar 2026 16:18:14 -0400 Subject: [PATCH] [IMP] script kill process by port: add protection and interactive menu --- script/process/kill_process_by_port.py | 73 +++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/script/process/kill_process_by_port.py b/script/process/kill_process_by_port.py index 89f1a14..0610320 100755 --- a/script/process/kill_process_by_port.py +++ b/script/process/kill_process_by_port.py @@ -8,6 +8,30 @@ import psutil STOP_PARENT_KILL = ["./odoo_bin.sh", "./run.sh"] +# Processes that must never be killed — killing these +# can crash the desktop session or the system. +PROTECTED_NAMES = { + "systemd", + "init", + "gnome-session", + "gnome-session-binary", + "gnome-shell", + "gdm", + "gdm3", + "gdm-session-worker", + "lightdm", + "sddm", + "Xorg", + "Xwayland", + "plasmashell", + "kwin_wayland", + "kwin_x11", + "loginctl", + "login", + "sshd", + "tmux: server", +} + def proc_desc(p: psutil.Process) -> str: try: @@ -131,6 +155,11 @@ def main(): default=1, help="Kill parent too", ) + ap.add_argument( + "--automatic", + action="store_true", + help="Ignore ask confirmation before killing", + ) args = ap.parse_args() if not (1 <= args.port <= 65535): @@ -151,20 +180,53 @@ def main(): print(f"\nListener PID {pid} ancestry:") for i, p in enumerate(chain): - prefix = " " + ("-> " if p == target else " ") - print(prefix + proc_desc(p)) + prefix = " " + ("-> " if p == target else " ") + print(f"[{i}]" + prefix + proc_desc(p)) if target is None: continue - if target.pid == 1 and not args.allow_pid1: + if target.pid == 1: print( - "Refus: la cible est PID 1 (systemd). Utilise plutôt systemctl pour arrêter le service.", - file=sys.stderr, + "Refus: la cible est PID 1 (systemd)." + " Utilise plutôt systemctl pour arrêter" + " le service.", + ) + continue + if target.name() in PROTECTED_NAMES: + print( + f"Refus: le process '{target.name()}' semble être protégé et dangereux à être arrêter.", ) continue action = "KILL" if args.force else "TERM" + + if not args.automatic: + has_response = False + ignore_kill = False + while not has_response and not ignore_kill: + confirm = ( + input( + f"Tuer ce processus index {args.nb_parent} (enter) ou mettre " + f"l'index [0 to {len(chain) - 1}] du " + f"process à tuer, (c/C) pour annuler : \n" + ) + .strip() + .lower() + ) + if not confirm: + has_response = True + continue + if confirm == "c": + ignore_kill = True + print("Cancel") + continue + if confirm.isdigit(): + has_response = True + target = chain[int(confirm)] + if ignore_kill: + continue + if args.kill_tree: print(f"Target: pid={target.pid} ({action}) + children (tree)") if not args.dry_run: @@ -173,7 +235,6 @@ def main(): print( "Toujours vivants:", ", ".join(str(p.pid) for p in alive), - file=sys.stderr, ) else: print(f"Target: pid={target.pid} ({action})")