Files
pristontale-eu-linux/ptlinux/gamescope_child_runtime.py

70 lines
1.9 KiB
Python

"""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())