diff --git a/core/archipelago/src/container/prod_orchestrator.rs b/core/archipelago/src/container/prod_orchestrator.rs index 37ae6330..fb05df92 100644 --- a/core/archipelago/src/container/prod_orchestrator.rs +++ b/core/archipelago/src/container/prod_orchestrator.rs @@ -362,11 +362,7 @@ fn ownership_already_correct(path: &str, host_uid_gid: &str) -> bool { } async fn ownership_already_correct_from_host(path: &str, host_uid_gid: &str) -> bool { - let Ok(out) = tokio::process::Command::new("sudo") - .args(["stat", "-c", "%u:%g", path]) - .output() - .await - else { + let Ok(out) = crate::update::host_sudo_output(&["stat", "-c", "%u:%g", path]).await else { return false; }; out.status.success() && String::from_utf8_lossy(&out.stdout).trim() == host_uid_gid diff --git a/core/archipelago/src/update.rs b/core/archipelago/src/update.rs index 69a3345d..13e1ee35 100644 --- a/core/archipelago/src/update.rs +++ b/core/archipelago/src/update.rs @@ -1496,6 +1496,25 @@ pub(crate) async fn host_sudo(args: &[&str]) -> Result .context("sudo systemd-run spawn failed") } +/// Same mechanism as `host_sudo` but captures stdout — for read-only probes +/// (e.g. `stat`) where the answer is in the output, not the exit status. +pub(crate) async fn host_sudo_output(args: &[&str]) -> Result { + let mut full: Vec<&str> = vec![ + "systemd-run", + "--wait", + "--quiet", + "--collect", + "--pipe", + "--", + ]; + full.extend_from_slice(args); + tokio::process::Command::new("sudo") + .args(&full) + .output() + .await + .context("sudo systemd-run output spawn failed") +} + /// Apply a downloaded update. Backs up current binaries, replaces with staged versions. pub async fn apply_update(data_dir: &Path) -> Result<()> { let _op = UPDATE_OP_LOCK.try_lock().map_err(|_| {