Added bubblewrap / apparmor fixes and diagnostic tools for troubleshooting it on related distros.
This commit is contained in:
@@ -22,6 +22,13 @@ from ptdiag.logs import (
|
||||
|
||||
from . import __version__
|
||||
from .command import CommandError, CommandOutcome, CommandRunner
|
||||
from .container_host import (
|
||||
ContainerHostReport,
|
||||
container_host_error,
|
||||
inspect_container_host,
|
||||
repair_container_host,
|
||||
repair_container_host_after_update,
|
||||
)
|
||||
from .depot import (
|
||||
DownloadOptions,
|
||||
SyncProgress,
|
||||
@@ -83,6 +90,15 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
|
||||
subparsers.add_parser("gui", help="open the native Linux dashboard")
|
||||
subparsers.add_parser("doctor", help="check cross-distribution dependencies")
|
||||
container_host = subparsers.add_parser(
|
||||
"container-host",
|
||||
help="check Bubblewrap and Ubuntu AppArmor for the Steam Runtime",
|
||||
)
|
||||
container_host.add_argument(
|
||||
"--repair",
|
||||
action="store_true",
|
||||
help="repair only recognized Ubuntu AppArmor profile states",
|
||||
)
|
||||
subparsers.add_parser(
|
||||
"runtime-bootstrap",
|
||||
help="download and verify the Steam Runtime launcher helper",
|
||||
@@ -250,12 +266,15 @@ def main(argv: Sequence[str] | None = None) -> int:
|
||||
try:
|
||||
if command == "gui":
|
||||
provision_umu_for_startup(paths)
|
||||
_container_host_startup_migration(paths)
|
||||
from .ui import run_dashboard
|
||||
|
||||
run_dashboard(paths)
|
||||
return 0
|
||||
if command == "doctor":
|
||||
return _doctor(arguments.json)
|
||||
if command == "container-host":
|
||||
return _container_host(arguments.repair, arguments.json)
|
||||
if command == "runtime-bootstrap":
|
||||
return _runtime_bootstrap(paths, arguments.json)
|
||||
if command == "login-diagnostics":
|
||||
@@ -384,6 +403,46 @@ def _doctor(as_json: bool) -> int:
|
||||
return 0 if report.ok else 1
|
||||
|
||||
|
||||
def _container_host(repair: bool, as_json: bool) -> int:
|
||||
report = repair_container_host() if repair else inspect_container_host()
|
||||
ok = _container_host_ok(report)
|
||||
payload = {"ok": ok, "container_host": report.to_dict()}
|
||||
if as_json:
|
||||
_print_json(payload)
|
||||
else:
|
||||
status = "ready" if report.ready else "blocked"
|
||||
print(f"Bubblewrap: {status} ({report.bwrap_path or 'not found'})")
|
||||
if report.active_profile_source:
|
||||
print(f"AppArmor: {report.active_profile_source}")
|
||||
elif report.apparmor_restrict_unprivileged_userns == "1":
|
||||
print(
|
||||
"AppArmor: unprivileged user namespaces are restricted; "
|
||||
"no bwrap profile found"
|
||||
)
|
||||
if report.repair_actions:
|
||||
for action in report.repair_actions:
|
||||
print(f"Repair: {action}")
|
||||
if report.repair_error:
|
||||
print(f"Repair failed: {report.repair_error}", file=sys.stderr)
|
||||
elif report.recommendation:
|
||||
print(f"Action: {report.recommendation}", file=sys.stderr)
|
||||
return 0 if ok else 1
|
||||
|
||||
|
||||
def _container_host_ok(report: ContainerHostReport) -> bool:
|
||||
return (
|
||||
report.ready
|
||||
and not report.broken_umu_profile_link
|
||||
and report.repair_error is None
|
||||
)
|
||||
|
||||
|
||||
def _container_host_startup_migration(paths: AppPaths) -> None:
|
||||
report = repair_container_host_after_update(paths)
|
||||
if report.repair_attempted and not _container_host_ok(report):
|
||||
print(f"Warning: {container_host_error(report)}", file=sys.stderr)
|
||||
|
||||
|
||||
def _runtime_bootstrap(paths: AppPaths, as_json: bool) -> int:
|
||||
_print_operation_status(as_json, 1, 1, "Preparing the Steam Runtime helper…")
|
||||
result = provision_umu(paths)
|
||||
@@ -1018,6 +1077,7 @@ def _runtime_issue_summary(stderr: str) -> dict[str, object]:
|
||||
futex_message = "the futex facility returned an unexpected error code"
|
||||
wrong_elf_message = "wrong elf class: elfclass64"
|
||||
dbghelp_assertion = "assertion failed: module->module.symtype != symdeferred"
|
||||
bwrap_uid_map_denied = "bwrap: setting up uid map: permission denied"
|
||||
missing_libraries = sorted(
|
||||
{
|
||||
library
|
||||
@@ -1038,6 +1098,7 @@ def _runtime_issue_summary(stderr: str) -> dict[str, object]:
|
||||
"mesa_egl_initialization_failed": "egl: failed to create dri2 screen" in folded,
|
||||
"steam_api_app_id_missing": "steamapi_init() failed; no appid found" in folded,
|
||||
"dbghelp_symdeferred_assertion_count": folded.count(dbghelp_assertion),
|
||||
"bubblewrap_uid_map_permission_denied": bwrap_uid_map_denied in folded,
|
||||
}
|
||||
|
||||
|
||||
@@ -1079,6 +1140,12 @@ def _print_game_outcome(
|
||||
"can mask the client failure that occurred immediately before it.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
if runtime_issues["bubblewrap_uid_map_permission_denied"]:
|
||||
print(
|
||||
"Ubuntu denied Bubblewrap's UID map before Proton started. Run "
|
||||
"`pristontale-eu container-host --repair` and retry.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
recommendation = runtime_issues.get("recommended_one_variable_comparison")
|
||||
if isinstance(recommendation, str):
|
||||
print(
|
||||
@@ -1188,7 +1255,7 @@ def _launcher_update(
|
||||
as_json,
|
||||
)
|
||||
return 0
|
||||
_print_operation_status(as_json, 1, 3, "Verifying the signed launcher release…")
|
||||
_print_operation_status(as_json, 1, 4, "Verifying the signed launcher release…")
|
||||
result = install_launcher_update(
|
||||
paths,
|
||||
manifest_url=manifest_url,
|
||||
@@ -1197,7 +1264,7 @@ def _launcher_update(
|
||||
_print_operation_status(
|
||||
as_json,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
"Launcher update installed; preparing the Steam Runtime helper…",
|
||||
)
|
||||
umu_result: UmuBootstrapResult | None = None
|
||||
@@ -1216,7 +1283,19 @@ def _launcher_update(
|
||||
umu_warning = warning_message
|
||||
if not as_json:
|
||||
print(f"Warning: {warning_message}", file=sys.stderr)
|
||||
_print_operation_status(as_json, 3, 3, "Launcher update and runtime check complete.")
|
||||
_print_operation_status(
|
||||
as_json,
|
||||
3,
|
||||
4,
|
||||
"Checking Steam Runtime sandbox permissions (authentication may be requested)…",
|
||||
)
|
||||
container_report = repair_container_host()
|
||||
container_warning = container_report.repair_error
|
||||
if not container_report.ready and container_warning is None:
|
||||
container_warning = container_report.recommendation
|
||||
if container_warning and not as_json:
|
||||
print(f"Warning: {container_warning}", file=sys.stderr)
|
||||
_print_operation_status(as_json, 4, 4, "Launcher update and runtime check complete.")
|
||||
_emit(
|
||||
{
|
||||
"ok": True,
|
||||
@@ -1226,6 +1305,10 @@ def _launcher_update(
|
||||
"managed_download": asdict(umu_result) if umu_result else None,
|
||||
"warning": umu_warning,
|
||||
},
|
||||
"container_host": {
|
||||
**container_report.to_dict(),
|
||||
"warning": container_warning,
|
||||
},
|
||||
},
|
||||
as_json,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user