chore: consolidate parallel-session WIP (HOLD — do not push)
Local snapshot of intermingled in-flight work, committed to unblock the encode
refactor (a clean ffmpeg_win.rs for the vbv-dedup follow-on). These hunks span
the same files and can't be cleanly split here; the commit bundles three
distinct workstreams that each belong in their own PR:
- logging rework (~43 files: level re-tiering, structured fields, `?e`,
hot-path flood latches)
- conflicting-host detection (detect.rs + detect/{linux,windows}.rs + wiring
in main.rs/mgmt.rs/Cargo.toml/docs/packaging)
- standby-sink DWM-stall attribution (windows/display_events.rs + capture/
vdisplay wiring)
NOT verified as a combination. NOT to be pushed until the refactor is done and
these are re-verified and reorganized into their proper per-workstream PRs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
//! Linux conflicting-host facts: `/proc` for running processes, the standard systemd unit dirs +
|
||||
//! flatpak app dirs + `PATH` for install markers. All best-effort and dependency-free (no
|
||||
//! subprocess spawns) — a missing `/proc` or an unreadable dir simply yields no evidence.
|
||||
|
||||
use super::{Evidence, Known};
|
||||
use std::path::Path;
|
||||
|
||||
/// Lowercased basenames of every process whose `/proc/<pid>/comm` we can read. `comm` is the
|
||||
/// kernel's 15-char command name — every host we match on (sunshine, apollo, vibeshine, vibepollo,
|
||||
/// luminalshine) fits within that, so no `/proc/<pid>/exe` readlink is needed.
|
||||
pub fn running_processes() -> Vec<String> {
|
||||
let mut out = Vec::new();
|
||||
let Ok(entries) = std::fs::read_dir("/proc") else {
|
||||
return out;
|
||||
};
|
||||
for entry in entries.flatten() {
|
||||
// Only numeric (pid) directories.
|
||||
if !entry
|
||||
.file_name()
|
||||
.to_str()
|
||||
.map(|n| n.bytes().all(|b| b.is_ascii_digit()))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if let Ok(comm) = std::fs::read_to_string(entry.path().join("comm")) {
|
||||
out.push(comm.trim().to_ascii_lowercase());
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// systemd unit registration + flatpak + `PATH` binary presence — the "installed" evidence.
|
||||
pub fn static_evidence(known: &Known) -> Vec<Evidence> {
|
||||
let mut ev = Vec::new();
|
||||
|
||||
// systemd units, system + per-user, in the dirs systemd actually reads.
|
||||
let home = std::env::var_os("HOME");
|
||||
let mut unit_dirs: Vec<String> = vec![
|
||||
"/etc/systemd/system".into(),
|
||||
"/run/systemd/system".into(),
|
||||
"/usr/lib/systemd/system".into(),
|
||||
"/lib/systemd/system".into(),
|
||||
"/etc/systemd/user".into(),
|
||||
"/usr/lib/systemd/user".into(),
|
||||
];
|
||||
if let Some(h) = &home {
|
||||
unit_dirs.push(format!("{}/.config/systemd/user", h.to_string_lossy()));
|
||||
}
|
||||
for unit in known.linux_units {
|
||||
let file = format!("{unit}.service");
|
||||
if unit_dirs.iter().any(|d| Path::new(d).join(&file).exists()) {
|
||||
ev.push(Evidence::Service { name: file });
|
||||
}
|
||||
}
|
||||
|
||||
// flatpak app installs (system + per-user).
|
||||
let mut flatpak_roots: Vec<String> = vec!["/var/lib/flatpak/app".into()];
|
||||
if let Some(h) = &home {
|
||||
flatpak_roots.push(format!("{}/.local/share/flatpak/app", h.to_string_lossy()));
|
||||
}
|
||||
for id in known.flatpaks {
|
||||
if flatpak_roots.iter().any(|r| Path::new(r).join(id).exists()) {
|
||||
ev.push(Evidence::Installed {
|
||||
at: format!("flatpak {id}"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// A matching binary on PATH (covers manual / package installs the unit/flatpak checks miss).
|
||||
let path = std::env::var_os("PATH");
|
||||
for bin in known.processes {
|
||||
if let Some(found) = find_on_path(bin, path.as_deref()) {
|
||||
ev.push(Evidence::Installed { at: found });
|
||||
}
|
||||
}
|
||||
|
||||
ev
|
||||
}
|
||||
|
||||
fn find_on_path(bin: &str, path: Option<&std::ffi::OsStr>) -> Option<String> {
|
||||
let dirs = path.map(std::env::split_paths).into_iter().flatten();
|
||||
// Always also probe the common bindirs, even if PATH is unset/narrow (e.g. a service context).
|
||||
let extra = ["/usr/bin", "/usr/local/bin", "/bin", "/usr/games"]
|
||||
.into_iter()
|
||||
.map(std::path::PathBuf::from);
|
||||
for dir in dirs.chain(extra) {
|
||||
let cand = dir.join(bin);
|
||||
if cand.is_file() {
|
||||
return Some(cand.to_string_lossy().into_owned());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
//! Windows conflicting-host facts: a Toolhelp process snapshot for what's running, the SCM for
|
||||
//! registered services, and `%ProgramFiles%` for on-disk installs. All best-effort — any failing
|
||||
//! query (no privilege, API error) yields no evidence rather than aborting startup.
|
||||
|
||||
use super::{Evidence, Known};
|
||||
use windows::Win32::Foundation::CloseHandle;
|
||||
use windows::Win32::System::Diagnostics::ToolHelp::{
|
||||
CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W, TH32CS_SNAPPROCESS,
|
||||
};
|
||||
use windows_service::service::ServiceAccess;
|
||||
use windows_service::service_manager::{ServiceManager, ServiceManagerAccess};
|
||||
|
||||
/// Lowercased executable basenames (without `.exe`) of every running process, via a Toolhelp
|
||||
/// snapshot. `szExeFile` is the module base name (e.g. `sunshine.exe`), not a full path.
|
||||
pub fn running_processes() -> Vec<String> {
|
||||
let mut out = Vec::new();
|
||||
// SAFETY: standard Toolhelp snapshot walk. The snapshot handle is closed on every exit path;
|
||||
// `entry` is fully initialized (dwSize set) before Process32FirstW reads it.
|
||||
unsafe {
|
||||
let Ok(snap) = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) else {
|
||||
return out;
|
||||
};
|
||||
// Zeroed then dwSize set — the canonical Toolhelp init (no reliance on a Default impl for
|
||||
// the 260-wide szExeFile array).
|
||||
let mut entry = PROCESSENTRY32W {
|
||||
dwSize: std::mem::size_of::<PROCESSENTRY32W>() as u32,
|
||||
..std::mem::zeroed()
|
||||
};
|
||||
if Process32FirstW(snap, &mut entry).is_ok() {
|
||||
loop {
|
||||
let end = entry
|
||||
.szExeFile
|
||||
.iter()
|
||||
.position(|&c| c == 0)
|
||||
.unwrap_or(entry.szExeFile.len());
|
||||
let name = String::from_utf16_lossy(&entry.szExeFile[..end]).to_ascii_lowercase();
|
||||
out.push(name.strip_suffix(".exe").unwrap_or(&name).to_string());
|
||||
if Process32NextW(snap, &mut entry).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let _ = CloseHandle(snap);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// SCM service registration + `%ProgramFiles%` install dirs — the "installed" evidence.
|
||||
pub fn static_evidence(known: &Known) -> Vec<Evidence> {
|
||||
let mut ev = Vec::new();
|
||||
for svc in known.win_services {
|
||||
if service_exists(svc) {
|
||||
ev.push(Evidence::Service {
|
||||
name: (*svc).to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
for dir in known.win_dirs {
|
||||
if let Some(at) = program_files_dir(dir) {
|
||||
ev.push(Evidence::Installed { at });
|
||||
}
|
||||
}
|
||||
ev
|
||||
}
|
||||
|
||||
/// True if a service by this name is registered with the SCM (running or stopped). Opening it with
|
||||
/// `QUERY_STATUS` fails cleanly when it doesn't exist.
|
||||
fn service_exists(name: &str) -> bool {
|
||||
let Ok(mgr) = ServiceManager::local_computer(None::<&str>, ServiceManagerAccess::CONNECT)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
mgr.open_service(name, ServiceAccess::QUERY_STATUS).is_ok()
|
||||
}
|
||||
|
||||
/// The install directory under any of the Program Files roots, if it exists.
|
||||
fn program_files_dir(dir: &str) -> Option<String> {
|
||||
for var in ["ProgramFiles", "ProgramW6432", "ProgramFiles(x86)"] {
|
||||
if let Some(base) = std::env::var_os(var) {
|
||||
let p = std::path::Path::new(&base).join(dir);
|
||||
if p.is_dir() {
|
||||
return Some(p.to_string_lossy().into_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
Reference in New Issue
Block a user