70 lines
1.9 KiB
Python
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())
|