"""Report the nested client status to the outer Gamescope supervisor.""" from __future__ import annotations import argparse import os from pathlib import Path import subprocess import sys from collections.abc import Sequence def _process_exit_status(returncode: int) -> int: if returncode < 0: return 128 + min(-returncode, 127) return min(returncode, 255) def run_and_record(command: Sequence[str], status_file: Path) -> int: if not command: raise ValueError("nested game command cannot be empty") try: process = subprocess.Popen([str(value) for value in command]) except OSError as exc: print(f"Could not start the nested game command: {exc}", file=sys.stderr) returncode = 127 else: try: returncode = int(process.wait()) except BaseException: if process.poll() is None: process.terminate() try: process.wait(timeout=2.0) except subprocess.TimeoutExpired: process.kill() process.wait() raise temporary = status_file.with_name(f".{status_file.name}.{os.getpid()}.tmp") try: temporary.write_text(f"{returncode}\n", encoding="ascii") os.replace(temporary, status_file) except OSError as exc: print(f"Could not report the nested game status: {exc}", file=sys.stderr) try: temporary.unlink() except FileNotFoundError: pass return _process_exit_status(returncode) def main(argv: Sequence[str] | None = None) -> int: parser = argparse.ArgumentParser() parser.add_argument("--status-file", required=True, type=Path) parser.add_argument("command", nargs=argparse.REMAINDER) arguments = parser.parse_args(argv) command = arguments.command if command and command[0] == "--": command = command[1:] try: return run_and_record(command, arguments.status_file) except ValueError as exc: print(f"Nested game launch failed: {exc}", file=sys.stderr) return 1 if __name__ == "__main__": raise SystemExit(main())