From 19194e73fc3d314060cb3defec24a0ded6da3710 Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Mon, 18 May 2026 17:59:47 -0400 Subject: [PATCH] Fenrir was not cleaning up after itself properly. Fixed several possible stale file bugs and hopefully this problem is now gone. --- src/fenrir | 7 +++- src/fenrirscreenreader/core/fenrirManager.py | 42 ++++++++++++------- .../core/remoteInstanceRegistry.py | 40 +++++++++++++++++- src/fenrirscreenreader/fenrirVersion.py | 2 +- 4 files changed, 72 insertions(+), 19 deletions(-) diff --git a/src/fenrir b/src/fenrir index cf2420e5..57c61761 100755 --- a/src/fenrir +++ b/src/fenrir @@ -106,14 +106,17 @@ def run_fenrir(): fenrirApp.proceed() except Exception as e: print(f"Error starting Fenrir: {e}", file=sys.stderr) + sys.exit(1) + except KeyboardInterrupt: + print("Interrupted", file=sys.stderr) + sys.exit(1) + finally: if fenrirApp and hasattr(fenrirApp, 'cleanup_on_error'): try: fenrirApp.cleanup_on_error() except Exception as cleanup_error: print( f"Error during cleanup: {cleanup_error}", file=sys.stderr) - sys.exit(1) - finally: if fenrirApp: del fenrirApp # Clean up PID file if it exists diff --git a/src/fenrirscreenreader/core/fenrirManager.py b/src/fenrirscreenreader/core/fenrirManager.py index 21a6e1c6..3a59d8e1 100644 --- a/src/fenrirscreenreader/core/fenrirManager.py +++ b/src/fenrirscreenreader/core/fenrirManager.py @@ -5,6 +5,7 @@ # By Chrys, Storm Dragon, and contributors. import os +import socket import signal import sys import time @@ -40,6 +41,7 @@ class FenrirManager: # Set signal handlers after successful initialization signal.signal(signal.SIGINT, self.capture_signal) signal.signal(signal.SIGTERM, self.capture_signal) + signal.signal(signal.SIGHUP, self.capture_signal) self.signal_handlers_set = True self.is_initialized = True @@ -381,9 +383,15 @@ class FenrirManager: time.sleep(0.6) for currentManager in self.environment["general"]["managerList"]: - if self.environment["runtime"][currentManager]: - self.environment["runtime"][currentManager].shutdown() - del self.environment["runtime"][currentManager] + try: + if ( + currentManager in self.environment["runtime"] + and self.environment["runtime"][currentManager] + ): + self.environment["runtime"][currentManager].shutdown() + del self.environment["runtime"][currentManager] + except Exception: + pass # Ignore errors during individual manager shutdown self.environment = None @@ -394,6 +402,7 @@ class FenrirManager: if self.signal_handlers_set: signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGTERM, signal.SIG_DFL) + signal.signal(signal.SIGHUP, signal.SIG_DFL) self.signal_handlers_set = False # Clean up any initialized managers @@ -454,7 +463,6 @@ class FenrirManager: # Clean up socket files that might not be removed by the driver try: socket_file = None - screen_driver = None if ( "runtime" in self.environment and "SettingsManager" in self.environment["runtime"] @@ -465,19 +473,9 @@ class FenrirManager: ].get_setting("remote", "socket_file") except Exception: pass # Use default socket file path - try: - screen_driver = self.environment["runtime"][ - "SettingsManager" - ].get_setting("screen", "driver") - except Exception: - pass if not socket_file: - if screen_driver == "vcsaDriver": - socket_file = "/tmp/fenrirscreenreader-deamon.sock" - if os.path.exists(socket_file): - os.unlink(socket_file) - + # Always clean up PID-specific socket pid_socket_file = ( "/tmp/fenrirscreenreader-" + str(os.getpid()) @@ -485,6 +483,20 @@ class FenrirManager: ) if os.path.exists(pid_socket_file): os.unlink(pid_socket_file) + + # Clean up main socket only if it is stale (not active) + main_socket_file = "/tmp/fenrirscreenreader-deamon.sock" + if os.path.exists(main_socket_file): + try: + test_sock = socket.socket( + socket.AF_UNIX, socket.SOCK_STREAM + ) + test_sock.settimeout(0.2) + test_sock.connect(main_socket_file) + except OSError: + os.unlink(main_socket_file) + finally: + test_sock.close() elif os.path.exists(socket_file): os.unlink(socket_file) remoteInstanceRegistry.remove_instance() diff --git a/src/fenrirscreenreader/core/remoteInstanceRegistry.py b/src/fenrirscreenreader/core/remoteInstanceRegistry.py index 5e8f046b..5733f3ab 100644 --- a/src/fenrirscreenreader/core/remoteInstanceRegistry.py +++ b/src/fenrirscreenreader/core/remoteInstanceRegistry.py @@ -28,6 +28,7 @@ def write_instance(instance_data): registry_dir = get_registry_dir() os.makedirs(registry_dir, mode=0o755, exist_ok=True) os.chmod(registry_dir, 0o755) + prune_stale_instances() instance_data["updated_at"] = time.time() instance_path = get_instance_file(instance_data.get("pid")) with open(instance_path, "w", encoding="utf-8") as instance_file: @@ -53,6 +54,39 @@ def process_exists(pid): return False +def prune_stale_instances(): + registry_dir = get_registry_dir() + try: + instance_files = os.listdir(registry_dir) + except FileNotFoundError: + return + + now = time.time() + for instance_name in instance_files: + instance_path = os.path.join(registry_dir, instance_name) + try: + with open(instance_path, "r", encoding="utf-8") as instance_file: + instance_data = json.load(instance_file) + pid = int(instance_data.get("pid", 0)) + updated_at = float(instance_data.get("updated_at", 0)) + except (OSError, ValueError, TypeError, json.JSONDecodeError): + try: + os.unlink(instance_path) + except OSError: + pass + continue + + if ( + not pid + or not process_exists(pid) + or now - updated_at > INSTANCE_TIMEOUT_SEC + ): + try: + os.unlink(instance_path) + except OSError: + pass + + def list_instances(): registry_dir = get_registry_dir() instances = [] @@ -72,7 +106,11 @@ def list_instances(): except (OSError, ValueError, TypeError, json.JSONDecodeError): continue - if not pid or not process_exists(pid) or now - updated_at > INSTANCE_TIMEOUT_SEC: + if ( + not pid + or not process_exists(pid) + or now - updated_at > INSTANCE_TIMEOUT_SEC + ): try: os.unlink(instance_path) except OSError: diff --git a/src/fenrirscreenreader/fenrirVersion.py b/src/fenrirscreenreader/fenrirVersion.py index 1e6dd448..2f6dffbc 100644 --- a/src/fenrirscreenreader/fenrirVersion.py +++ b/src/fenrirscreenreader/fenrirVersion.py @@ -4,5 +4,5 @@ # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributors. -version = "2026.05.14" +version = "2026.05.18" code_name = "testing"