diff --git a/burrow-gtk/Cargo.lock b/burrow-gtk/Cargo.lock index fce2a3b..93ff94a 100644 --- a/burrow-gtk/Cargo.lock +++ b/burrow-gtk/Cargo.lock @@ -26,6 +26,55 @@ dependencies = [ "memchr", ] +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "anyhow" version = "1.0.79" @@ -174,9 +223,11 @@ name = "burrow-gtk" version = "0.1.0" dependencies = [ "anyhow", + "colog", "gettext-rs", "glib-build-tools", "hyper-util", + "log", "prost", "prost-types", "relm4", @@ -242,12 +293,62 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "colog" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c426b7af8d5e0ad79de6713996632ce31f0d68ba84068fb0d654b396e519df0" +dependencies = [ + "colored", + "env_logger", + "log", +] + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys 0.48.0", +] + [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -797,6 +898,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "1.4.1" @@ -871,6 +978,12 @@ dependencies = [ "hashbrown 0.14.3", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.13.0" @@ -971,9 +1084,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "malloc_buf" @@ -1816,6 +1929,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "version-compare" version = "0.1.1" diff --git a/burrow-gtk/Cargo.toml b/burrow-gtk/Cargo.toml index b73d936..abeffc4 100644 --- a/burrow-gtk/Cargo.toml +++ b/burrow-gtk/Cargo.toml @@ -15,6 +15,8 @@ prost = "0.13" prost-types = "0.13" hyper-util = "0.1.6" tower = "0.4.13" +log = "0.4.22" +colog = "1.3.0" [build-dependencies] anyhow = "1.0" diff --git a/burrow-gtk/src/components/settings/daemon_group.rs b/burrow-gtk/src/components/settings/daemon_group.rs index 73f647b..4436d6e 100644 --- a/burrow-gtk/src/components/settings/daemon_group.rs +++ b/burrow-gtk/src/components/settings/daemon_group.rs @@ -48,7 +48,6 @@ impl AsyncComponent for DaemonGroup { root: Self::Root, sender: AsyncComponentSender, ) -> AsyncComponentParts { - // Should be impossible to panic here let model = DaemonGroup { system_setup: init.system_setup, daemon_client: init.daemon_client.clone(), @@ -68,45 +67,9 @@ impl AsyncComponent for DaemonGroup { ) { match msg { DaemonGroupMsg::LaunchLocal => { - // TODO: Handle error condition - - const BURROW_LOCAL_DAEMON_PATH: &str = "/tmp/burrow-detached-daemon"; - - let burrow_original_bin = std::env::vars() - .find(|(k, _)| k == "APPDIR") - .map(|(_, v)| v + "/usr/bin/burrow") - .unwrap_or("/usr/bin/burrow".to_owned()); - - Command::new("cp") - .arg(&burrow_original_bin) - .arg(BURROW_LOCAL_DAEMON_PATH) - .output() - .unwrap(); - - let mut burrow_bin = - String::from_utf8(Command::new("mktemp").output().unwrap().stdout).unwrap(); - burrow_bin.pop(); - - let privileged_spawn_script = format!( - r#"chmod +x {} -setcap CAP_NET_BIND_SERVICE,CAP_NET_ADMIN+eip {}"#, - BURROW_LOCAL_DAEMON_PATH, BURROW_LOCAL_DAEMON_PATH - ) - .replace('\n', "&&"); - - Command::new("pkexec") - .arg("sh") - .arg("-c") - .arg(privileged_spawn_script) - .arg(&burrow_bin) - .output() - .unwrap(); - - Command::new(BURROW_LOCAL_DAEMON_PATH) - .env("RUST_LOG", "debug") - .arg("daemon") - .spawn() - .unwrap(); + if let Err(e) = launch_local() { + error!("Failed to launch local daemon at: {}", e); + }; } DaemonGroupMsg::DaemonStateChange => { self.already_running = self.daemon_client.lock().await.is_some(); @@ -114,3 +77,49 @@ setcap CAP_NET_BIND_SERVICE,CAP_NET_ADMIN+eip {}"#, } } } + +fn launch_local() -> Result<()> { + const BURROW_LOCAL_DAEMON_PATH: &str = "/tmp/burrow-detached-daemon"; + + let burrow_original_bin = std::env::vars() + .find(|(k, _)| k == "APPDIR") + .map(|(_, v)| v + "/usr/bin/burrow") + .unwrap_or("/usr/bin/burrow".to_owned()); + + Command::new("cp") + .arg(&burrow_original_bin) + .arg(BURROW_LOCAL_DAEMON_PATH) + .output() + .with_context(|| { + format!( + "Copying {} to {}", + burrow_original_bin, BURROW_LOCAL_DAEMON_PATH + ) + })?; + + let mut burrow_bin = String::from_utf8(Command::new("mktemp").output()?.stdout)?; + burrow_bin.pop(); + + let privileged_spawn_script = format!( + r#"chmod +x {} +setcap CAP_NET_BIND_SERVICE,CAP_NET_ADMIN+eip {}"#, + BURROW_LOCAL_DAEMON_PATH, BURROW_LOCAL_DAEMON_PATH + ) + .replace('\n', "&&"); + + // Need to be more careful here. + Command::new("pkexec") + .arg("sh") + .arg("-c") + .arg(privileged_spawn_script) + .arg(&burrow_bin) + .output() + .with_context(|| format!("Priviledged call to {}", burrow_bin))?; + + Command::new(BURROW_LOCAL_DAEMON_PATH) + .env("RUST_LOG", "debug") + .arg("daemon") + .spawn()?; + + Ok(()) +} diff --git a/burrow-gtk/src/components/settings/diag_group.rs b/burrow-gtk/src/components/settings/diag_group.rs index 9e1bcff..28cbc9c 100644 --- a/burrow-gtk/src/components/settings/diag_group.rs +++ b/burrow-gtk/src/components/settings/diag_group.rs @@ -17,18 +17,18 @@ pub struct DiagGroupInit { } impl DiagGroup { - async fn new(daemon_client: Arc>>) -> Result { + async fn new(daemon_client: Arc>>) -> Self { let system_setup = SystemSetup::new(); let daemon_running = daemon_client.lock().await.is_some(); - Ok(Self { - service_installed: system_setup.is_service_installed()?, - socket_installed: system_setup.is_socket_installed()?, - socket_enabled: system_setup.is_socket_enabled()?, + Self { + service_installed: system_setup.is_service_installed(), + socket_installed: system_setup.is_socket_installed(), + socket_enabled: system_setup.is_socket_enabled(), daemon_running, system_setup, daemon_client, - }) + } } } @@ -95,7 +95,7 @@ impl AsyncComponent for DiagGroup { sender: AsyncComponentSender, ) -> AsyncComponentParts { // Should be impossible to panic here - let model = DiagGroup::new(init.daemon_client).await.unwrap(); + let model = DiagGroup::new(init.daemon_client).await; let widgets = view_output!(); @@ -111,7 +111,7 @@ impl AsyncComponent for DiagGroup { match msg { DiagGroupMsg::Refresh => { // Should be impossible to panic here - *self = Self::new(Arc::clone(&self.daemon_client)).await.unwrap(); + *self = Self::new(Arc::clone(&self.daemon_client)).await; } } } diff --git a/burrow-gtk/src/diag.rs b/burrow-gtk/src/diag.rs index ab4757e..94a29e1 100644 --- a/burrow-gtk/src/diag.rs +++ b/burrow-gtk/src/diag.rs @@ -4,7 +4,6 @@ use std::{fmt::Display, fs, process::Command}; const SYSTEMD_SOCKET_LOC: &str = "/etc/systemd/system/burrow.socket"; const SYSTEMD_SERVICE_LOC: &str = "/etc/systemd/system/burrow.service"; -// I don't like this type very much. #[derive(Debug, Clone, Copy)] pub enum StatusTernary { True, @@ -33,35 +32,41 @@ impl SystemSetup { } } - pub fn is_service_installed(&self) -> Result { + pub fn is_service_installed(&self) -> StatusTernary { match self { - SystemSetup::Systemd => Ok(fs::metadata(SYSTEMD_SERVICE_LOC).is_ok().into()), - SystemSetup::AppImage => Ok(StatusTernary::NA), - SystemSetup::Other => Ok(StatusTernary::NA), + SystemSetup::Systemd => fs::metadata(SYSTEMD_SERVICE_LOC).is_ok().into(), + SystemSetup::AppImage => StatusTernary::NA, + SystemSetup::Other => StatusTernary::NA, } } - pub fn is_socket_installed(&self) -> Result { + pub fn is_socket_installed(&self) -> StatusTernary { match self { - SystemSetup::Systemd => Ok(fs::metadata(SYSTEMD_SOCKET_LOC).is_ok().into()), - SystemSetup::AppImage => Ok(StatusTernary::NA), - SystemSetup::Other => Ok(StatusTernary::NA), + SystemSetup::Systemd => fs::metadata(SYSTEMD_SOCKET_LOC).is_ok().into(), + SystemSetup::AppImage => StatusTernary::NA, + SystemSetup::Other => StatusTernary::NA, } } - pub fn is_socket_enabled(&self) -> Result { + pub fn is_socket_enabled(&self) -> StatusTernary { match self { SystemSetup::Systemd => { - let output = Command::new("systemctl") + let Ok(output) = Command::new("systemctl") .arg("is-enabled") .arg("burrow.socket") - .output()? - .stdout; - let output = String::from_utf8(output)?; - Ok((output == "enabled\n").into()) + .output() + .map(|o| o.stdout) + .inspect_err(|e| { + error!("Failed to run `systemctl is-enabled burrow.socket` {}", e) + }) + else { + return StatusTernary::NA; + }; + let output = String::from_utf8(output).unwrap(); + (output == "enabled\n").into() } - SystemSetup::AppImage => Ok(StatusTernary::NA), - SystemSetup::Other => Ok(StatusTernary::NA), + SystemSetup::AppImage => StatusTernary::NA, + SystemSetup::Other => StatusTernary::NA, } } } diff --git a/burrow-gtk/src/main.rs b/burrow-gtk/src/main.rs index 66e6b36..202b930 100644 --- a/burrow-gtk/src/main.rs +++ b/burrow-gtk/src/main.rs @@ -1,4 +1,5 @@ -use anyhow::Result; +use anyhow::{Context, Result}; +use log::error; pub mod components; mod daemon; @@ -8,5 +9,8 @@ mod diag; mod config; fn main() { + colog::default_builder() + .filter(None, log::LevelFilter::Error) + .init(); components::App::run(); }