fix(windows-host): second-host guard — classify ACCESS_DENIED on the instance mutex as in-use
On-glass the SCM service creates Global\punktfunk-vdisplay-manager as SYSTEM, so a second elevated-admin host's CreateMutexW fails ACCESS_DENIED (the implicit open is checked against the SYSTEM DACL) before the ALREADY_EXISTS branch can fire — right refusal, wrong message. Map it to the same loud "another instance is live" error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -223,21 +223,28 @@ pub(crate) fn control_device_handle() -> Option<HANDLE> {
|
|||||||
/// second process fail its vdisplay open LOUDLY instead. Held, never released, for the process
|
/// second process fail its vdisplay open LOUDLY instead. Held, never released, for the process
|
||||||
/// lifetime; the OS reclaims it (and frees the name) when the process exits, however it exits.
|
/// lifetime; the OS reclaims it (and frees the name) when the process exits, however it exits.
|
||||||
fn acquire_single_instance() -> Result<OwnedHandle> {
|
fn acquire_single_instance() -> Result<OwnedHandle> {
|
||||||
// SAFETY: plain FFI create of a named mutex; the returned handle (checked by `?`) is solely
|
const IN_USE: &str = "another punktfunk-host process is already managing pf-vdisplay on this \
|
||||||
// owned by the `OwnedHandle`, and `GetLastError` is read immediately after the create — the
|
machine — refusing to touch the driver (a second manager's startup CLEAR_ALL would raze \
|
||||||
// documented ERROR_ALREADY_EXISTS protocol for pre-existing named objects.
|
the live host's monitors mid-stream). Stop the other instance (e.g. `punktfunk-host \
|
||||||
|
service stop`) first.";
|
||||||
|
// SAFETY: plain FFI create of a named mutex; the returned handle (checked) is solely owned by
|
||||||
|
// the `OwnedHandle`, and `GetLastError` is read immediately after the create — the documented
|
||||||
|
// ERROR_ALREADY_EXISTS protocol for pre-existing named objects.
|
||||||
unsafe {
|
unsafe {
|
||||||
let h = CreateMutexW(None, false, w!("Global\\punktfunk-vdisplay-manager"))
|
let h = match CreateMutexW(None, false, w!("Global\\punktfunk-vdisplay-manager")) {
|
||||||
.context("CreateMutexW(punktfunk-vdisplay single-instance guard)")?;
|
Ok(h) => h,
|
||||||
|
// The name exists but its creator's DACL denies this token the implicit OPEN (the SCM
|
||||||
|
// service creates it as SYSTEM; a second elevated-admin host lands here instead of in
|
||||||
|
// the ALREADY_EXISTS branch — validated on-glass). Same meaning: an instance is live.
|
||||||
|
Err(e) if e.code().0 == 0x8007_0005u32 as i32 => anyhow::bail!("{IN_USE}"),
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e).context("CreateMutexW(punktfunk-vdisplay single-instance guard)");
|
||||||
|
}
|
||||||
|
};
|
||||||
let already = GetLastError() == ERROR_ALREADY_EXISTS;
|
let already = GetLastError() == ERROR_ALREADY_EXISTS;
|
||||||
let owned = OwnedHandle::from_raw_handle(h.0 as _);
|
let owned = OwnedHandle::from_raw_handle(h.0 as _);
|
||||||
if already {
|
if already {
|
||||||
anyhow::bail!(
|
anyhow::bail!("{IN_USE}");
|
||||||
"another punktfunk-host process is already managing pf-vdisplay on this machine — \
|
|
||||||
refusing to touch the driver (a second manager's startup CLEAR_ALL would raze the \
|
|
||||||
live host's monitors mid-stream). Stop the other instance (e.g. `punktfunk-host \
|
|
||||||
service stop`) first."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Ok(owned)
|
Ok(owned)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user