From fbfa450e4ab962eccaf401c1f72e081fd5f88b92 Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Tue, 28 Apr 2026 00:21:42 -0300 Subject: [PATCH] fix(sync): keep uvc recovery aligned with runtime policy --- Cargo.lock | 6 +-- client/Cargo.toml | 2 +- common/Cargo.toml | 2 +- server/Cargo.toml | 2 +- server/src/gadget/enumeration_recovery.rs | 6 ++- .../tests/server_gadget_include_contract.rs | 45 ++++++++++++++++++- 6 files changed, 55 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7204e32..f0cca73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1642,7 +1642,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "lesavka_client" -version = "0.14.34" +version = "0.14.35" dependencies = [ "anyhow", "async-stream", @@ -1676,7 +1676,7 @@ dependencies = [ [[package]] name = "lesavka_common" -version = "0.14.34" +version = "0.14.35" dependencies = [ "anyhow", "base64", @@ -1688,7 +1688,7 @@ dependencies = [ [[package]] name = "lesavka_server" -version = "0.14.34" +version = "0.14.35" dependencies = [ "anyhow", "base64", diff --git a/client/Cargo.toml b/client/Cargo.toml index 71865ef..dffadec 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -4,7 +4,7 @@ path = "src/main.rs" [package] name = "lesavka_client" -version = "0.14.34" +version = "0.14.35" edition = "2024" [dependencies] diff --git a/common/Cargo.toml b/common/Cargo.toml index 9c23066..883ff7e 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lesavka_common" -version = "0.14.34" +version = "0.14.35" edition = "2024" build = "build.rs" diff --git a/server/Cargo.toml b/server/Cargo.toml index 0c081b3..04f0db0 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -10,7 +10,7 @@ bench = false [package] name = "lesavka_server" -version = "0.14.34" +version = "0.14.35" edition = "2024" autobins = false diff --git a/server/src/gadget/enumeration_recovery.rs b/server/src/gadget/enumeration_recovery.rs index 1463c37..50d072d 100644 --- a/server/src/gadget/enumeration_recovery.rs +++ b/server/src/gadget/enumeration_recovery.rs @@ -85,6 +85,10 @@ impl UsbGadget { env::var("LESAVKA_CORE_HELPER").unwrap_or_else(|_| "/usr/local/bin/lesavka-core.sh".into()) } + fn uvc_fallback_mode() -> String { + env::var("LESAVKA_UVC_FALLBACK").unwrap_or_else(|_| "0".to_string()) + } + fn run_forced_core_rebuild(&self) -> Result { let helper = Self::core_helper_path(); let output = Command::new(&helper) @@ -92,7 +96,7 @@ impl UsbGadget { .env("LESAVKA_ATTACH_WRITE_UDC", "1") .env("LESAVKA_DETACH_CLEAR_UDC", "1") .env("LESAVKA_RELOAD_UVCVIDEO", "1") - .env("LESAVKA_UVC_FALLBACK", "1") + .env("LESAVKA_UVC_FALLBACK", Self::uvc_fallback_mode()) .env( "LESAVKA_UVC_CODEC", env::var("LESAVKA_UVC_CODEC").unwrap_or_else(|_| "mjpeg".to_string()), diff --git a/testing/tests/server_gadget_include_contract.rs b/testing/tests/server_gadget_include_contract.rs index a9b056c..c4d9e01 100644 --- a/testing/tests/server_gadget_include_contract.rs +++ b/testing/tests/server_gadget_include_contract.rs @@ -402,13 +402,56 @@ printf 'configured\n' > "$LESAVKA_GADGET_SYSFS_ROOT/class/udc/fake-ctrl.usb/stat "LESAVKA_ATTACH_WRITE_UDC=1", "LESAVKA_DETACH_CLEAR_UDC=1", "LESAVKA_RELOAD_UVCVIDEO=1", - "LESAVKA_UVC_FALLBACK=1", + "LESAVKA_UVC_FALLBACK=0", "LESAVKA_UVC_CODEC=mjpeg", ] { assert!(dumped.contains(line), "{line} missing from {dumped}"); } } + #[test] + #[serial] + fn recover_enumeration_honors_explicit_uvc_fallback_override() { + let dir = tempdir().expect("tempdir"); + let ctrl = "fake-ctrl.usb"; + build_fake_tree(dir.path(), ctrl, "lesavka-test", "not attached"); + let helper = dir.path().join("fake-core-env-override.sh"); + let env_dump = dir.path().join("helper-env-override.txt"); + write_helper( + &helper, + r#"#!/usr/bin/env bash +set -euo pipefail +cat > "$LESAVKA_HELPER_ENV_DUMP" < "$LESAVKA_GADGET_SYSFS_ROOT/class/udc/fake-ctrl.usb/state" +"#, + ); + + with_fake_roots(&dir.path().join("sys"), &dir.path().join("cfg"), || { + with_fast_recovery_env(&helper, || { + with_var("LESAVKA_UVC_FALLBACK", Some("1"), || { + with_var( + "LESAVKA_HELPER_ENV_DUMP", + Some(env_dump.to_string_lossy().to_string()), + || { + let gadget = UsbGadget::new("lesavka-test"); + gadget + .recover_enumeration() + .expect("forced rebuild should recover fake UDC"); + }, + ); + }); + }); + }); + + let dumped = std::fs::read_to_string(env_dump).expect("read helper env dump"); + assert!( + dumped.contains("LESAVKA_UVC_FALLBACK=1"), + "explicit fallback override missing from {dumped}" + ); + } + #[test] #[serial] fn recover_enumeration_reports_clear_failure_when_helper_leaves_udc_unattached() {