mirror of
https://github.com/lucannez64/darling-lol.git
synced 2026-10-26 19:47:42 +00:00
62 lines
2.7 KiB
Python
62 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Read-only, fail-closed rootless maintenance preflight. Never signal a process."""
|
|
import os
|
|
from pathlib import Path
|
|
|
|
|
|
def client_active(prefix, *, processes=None):
|
|
"""Check exact-prefix mappings; only vanished processes may be skipped."""
|
|
paths = [str(prefix / name) + '/' for name in (
|
|
'Applications/Riot Client.app', 'Applications/League of Legends.app',
|
|
'Users/Shared/Riot Games')]
|
|
namespace_map = Path('/proc/self/uid_map').read_text()
|
|
for process in Path('/proc').iterdir() if processes is None else processes:
|
|
if not process.name.isdigit():
|
|
continue
|
|
try:
|
|
if process.stat().st_uid != os.getuid():
|
|
continue
|
|
# The outer live-marker gate excludes earlier Darling namespaces.
|
|
# Host processes are not ours to inspect; their maps are commonly
|
|
# unreadable from a child user namespace (including systemd --user).
|
|
if processes is None and (process / 'uid_map').read_text() != namespace_map:
|
|
continue
|
|
mappings = (process / 'maps').read_text()
|
|
if any(path in mappings for path in paths):
|
|
return True
|
|
except (FileNotFoundError, ProcessLookupError):
|
|
# Process exited between enumeration and inspection.
|
|
continue
|
|
except OSError as error:
|
|
raise RuntimeError(f'Cannot inspect process {process.name}; cannot establish that the prefix is idle: {error}') from error
|
|
return False
|
|
|
|
|
|
def main():
|
|
prefix = Path(os.environ.get('DPREFIX', str(Path.home() / '.darling'))).resolve()
|
|
try:
|
|
pid = int((prefix / '.init.pid').read_text().strip())
|
|
except FileNotFoundError:
|
|
pid = 0
|
|
except (OSError, ValueError):
|
|
raise SystemExit('Cannot validate prefix server marker; inspect it before maintenance.')
|
|
if pid > 0:
|
|
try:
|
|
status = (Path('/proc') / str(pid) / 'status').read_text()
|
|
if not any(line.startswith('State:') and line.split()[1] == 'Z' for line in status.splitlines()):
|
|
raise SystemExit('Prefix has a live server marker; exit Riot/League and run darling shutdown in the ORIGINAL namespace before updating. No process was stopped.')
|
|
except (FileNotFoundError, ProcessLookupError):
|
|
pass
|
|
except OSError as error:
|
|
raise SystemExit(f'Cannot validate prefix server marker: {error}') from error
|
|
try:
|
|
active = client_active(prefix)
|
|
except (OSError, RuntimeError) as error:
|
|
raise SystemExit(str(error)) from error
|
|
if active:
|
|
raise SystemExit('A client maps this prefix; exit it before rootless maintenance. No process was stopped.')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|