From bc1ec9aa3e0a60578f912b3decaece2a5bc79b56 Mon Sep 17 00:00:00 2001 From: ssmithx Date: Mon, 29 Jun 2026 13:17:20 +0000 Subject: [PATCH] fix(openwrt): use full opkg path and pre-check availability `channel.exec()` doesn't source the shell profile, so PATH may not include /usr/bin on some routers. Using /usr/bin/opkg explicitly avoids exit-127 surprises. Added opkg_check() to give a clear error ("firmware may not support package management") before attempting opkg_update, rather than a confusing "command not found" exit code. Also split the BusyBox-hostile `grep -v 'all\|noarch'` into two separate greps for the arch-detection fallback. Co-Authored-By: Claude Sonnet 4.6 --- core/openwrt/src/opkg.rs | 20 ++++++++++++++++---- core/openwrt/src/tollgate/install.rs | 4 ++-- core/openwrt/src/tollgate/mod.rs | 1 + 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/core/openwrt/src/opkg.rs b/core/openwrt/src/opkg.rs index 4ee0b45f..6f66e0a7 100644 --- a/core/openwrt/src/opkg.rs +++ b/core/openwrt/src/opkg.rs @@ -4,31 +4,43 @@ use tracing::info; use crate::Router; impl Router { + /// Verify opkg is available, returning a clear error if not. + pub fn opkg_check(&self) -> Result<()> { + let (_, code) = self.run("test -x /usr/bin/opkg")?; + if code != 0 { + anyhow::bail!( + "opkg not found at /usr/bin/opkg — this router's firmware may not \ + support package management (TollGate requires a standard OpenWrt build)" + ); + } + Ok(()) + } + /// `opkg update` — refresh package lists. pub fn opkg_update(&self) -> Result<()> { info!("[{}] opkg update", self.host); - self.run_ok("opkg update")?; + self.run_ok("/usr/bin/opkg update")?; Ok(()) } /// Install a package, skipping if already installed. pub fn opkg_install(&self, package: &str) -> Result<()> { // Check if already installed to avoid unnecessary network traffic. - let (_, code) = self.run(&format!("opkg list-installed | grep -q '^{} '", package))?; + let (_, code) = self.run(&format!("/usr/bin/opkg list-installed | grep -q '^{} '", package))?; if code == 0 { info!("[{}] {} already installed", self.host, package); return Ok(()); } info!("[{}] opkg install {}", self.host, package); - self.run_ok(&format!("opkg install {}", package))?; + self.run_ok(&format!("/usr/bin/opkg install {}", package))?; Ok(()) } /// Remove a package. pub fn opkg_remove(&self, package: &str) -> Result<()> { info!("[{}] opkg remove {}", self.host, package); - self.run_ok(&format!("opkg remove {}", package))?; + self.run_ok(&format!("/usr/bin/opkg remove {}", package))?; Ok(()) } } diff --git a/core/openwrt/src/tollgate/install.rs b/core/openwrt/src/tollgate/install.rs index 64b9a5e6..53a37398 100644 --- a/core/openwrt/src/tollgate/install.rs +++ b/core/openwrt/src/tollgate/install.rs @@ -35,7 +35,7 @@ pub fn install_tollgate(router: &Router) -> Result<()> { // Package not in any feed — download the .ipk directly. let arch = router - .run_ok("opkg print-architecture | grep -v 'all\\|noarch' | tail -1 | awk '{print $2}'")?; + .run_ok("/usr/bin/opkg print-architecture | grep -v all | grep -v noarch | tail -1 | awk '{print $2}'")?; let arch = arch.trim(); let url = ipk_url(arch).ok_or_else(|| { @@ -50,7 +50,7 @@ pub fn install_tollgate(router: &Router) -> Result<()> { router.run_ok(&format!("wget -O /tmp/tollgate.ipk '{}'", url))?; // Capture stderr too — BusyBox opkg exits 0 even on "Cannot install" failures. - let (out, _code) = router.run("opkg install --force-depends /tmp/tollgate.ipk 2>&1")?; + let (out, _code) = router.run("/usr/bin/opkg install --force-depends /tmp/tollgate.ipk 2>&1")?; router.run_ok("rm -f /tmp/tollgate.ipk")?; if out.contains("Cannot install") || out.contains("errors encountered") { diff --git a/core/openwrt/src/tollgate/mod.rs b/core/openwrt/src/tollgate/mod.rs index a756a675..dea969b7 100644 --- a/core/openwrt/src/tollgate/mod.rs +++ b/core/openwrt/src/tollgate/mod.rs @@ -19,6 +19,7 @@ use crate::Router; pub async fn provision(router: &Router, config: &TollGateConfig) -> Result<()> { info!("[{}] Starting TollGate provisioning", router.host); + router.opkg_check()?; router.opkg_update()?; install_tollgate(router)?; config::apply(router, config)?;