diff --git a/local/recipes/system/redbear-polkit/source/src/main.rs b/local/recipes/system/redbear-polkit/source/src/main.rs index 4f5cd65a..64b0d8d0 100644 --- a/local/recipes/system/redbear-polkit/source/src/main.rs +++ b/local/recipes/system/redbear-polkit/source/src/main.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, env, error::Error, process}; +use std::{collections::HashMap, env, error::Error, path::Path, process, thread, time::Duration}; use tokio::runtime::Builder as RuntimeBuilder; use zbus::{ @@ -34,6 +34,21 @@ fn usage() -> &'static str { "Usage: redbear-polkit [--help]" } +async fn wait_for_dbus_socket() { + let socket_path = env::var("DBUS_STARTER_ADDRESS") + .ok() + .and_then(|addr| addr.strip_prefix("unix:path=").map(String::from)) + .unwrap_or_else(|| "/run/dbus/system_bus_socket".to_string()); + + for _ in 0..30 { + if tokio::net::UnixStream::connect(&socket_path).await.is_ok() { + return; + } + tokio::time::sleep(Duration::from_secs(1)).await; + } + eprintln!("redbear-polkit: timed out waiting for D-Bus socket at {socket_path}"); +} + fn parse_args() -> Result { let mut args = env::args().skip(1); @@ -134,25 +149,34 @@ impl PolicyKitAuthority { } async fn run_daemon() -> Result<(), Box> { - eprintln!("redbear-polkit: startup begin"); - let _authority_path = parse_object_path(AUTHORITY_PATH)?; - eprintln!("redbear-polkit: object paths parsed"); + wait_for_dbus_socket().await; - eprintln!("redbear-polkit: starter address={:?}", env::var("DBUS_STARTER_ADDRESS").ok()); - eprintln!("redbear-polkit: building D-Bus connection"); - let connection = system_connection_builder()? - .name(BUS_NAME)? - .serve_at(AUTHORITY_PATH, PolicyKitAuthority)? - .build() - .await?; + let mut last_err = None; + for attempt in 1..=5 { + let _authority_path = parse_object_path(AUTHORITY_PATH)?; - eprintln!("redbear-polkit: registered {BUS_NAME} on the system bus"); - - wait_for_shutdown().await?; - drop(connection); - eprintln!("redbear-polkit: received shutdown signal, exiting cleanly"); - - Ok(()) + match system_connection_builder()? + .name(BUS_NAME)? + .serve_at(AUTHORITY_PATH, PolicyKitAuthority)? + .build() + .await + { + Ok(connection) => { + eprintln!("redbear-polkit: registered {BUS_NAME} on the system bus"); + wait_for_shutdown().await?; + drop(connection); + return Ok(()); + } + Err(err) => { + if attempt < 5 { + eprintln!("redbear-polkit: attempt {attempt}/5 failed ({err}), retrying in 2s..."); + tokio::time::sleep(Duration::from_secs(2)).await; + } + last_err = Some(err.into()); + } + } + } + Err(last_err.unwrap()) } fn main() { diff --git a/local/recipes/system/redbear-sessiond/source/src/main.rs b/local/recipes/system/redbear-sessiond/source/src/main.rs index 296b55b2..6c36dd75 100644 --- a/local/recipes/system/redbear-sessiond/source/src/main.rs +++ b/local/recipes/system/redbear-sessiond/source/src/main.rs @@ -8,6 +8,7 @@ use std::{ env, error::Error, process, + time::Duration, }; use device_map::DeviceMap; @@ -56,6 +57,21 @@ fn parse_object_path(path: &str) -> Result> { Ok(OwnedObjectPath::try_from(path.to_owned())?) } +async fn wait_for_dbus_socket() { + let socket_path = env::var("DBUS_STARTER_ADDRESS") + .ok() + .and_then(|addr| addr.strip_prefix("unix:path=").map(String::from)) + .unwrap_or_else(|| "/run/dbus/system_bus_socket".to_string()); + + for _ in 0..30 { + if tokio::net::UnixStream::connect(&socket_path).await.is_ok() { + return; + } + tokio::time::sleep(Duration::from_secs(1)).await; + } + eprintln!("redbear-sessiond: timed out waiting for D-Bus socket at {socket_path}"); +} + fn system_connection_builder() -> Result, Box> { if let Ok(address) = env::var("DBUS_STARTER_ADDRESS") { Ok(ConnectionBuilder::address(Address::try_from(address.as_str())?)?) @@ -90,39 +106,43 @@ async fn wait_for_shutdown() -> Result<(), Box> { } async fn run_daemon() -> Result<(), Box> { - eprintln!("redbear-sessiond: startup begin"); - let session_path = parse_object_path(SESSION_PATH)?; - let seat_path = parse_object_path(SEAT_PATH)?; - let user_path = parse_object_path(USER_PATH)?; - eprintln!("redbear-sessiond: object paths parsed"); + wait_for_dbus_socket().await; - let session = LoginSession::new(seat_path.clone(), user_path, DeviceMap::new()); - let seat = LoginSeat::new(session_path.clone()); - let manager = LoginManager::new(session_path, seat_path); + let mut last_err = None; + for attempt in 1..=5 { + let session_path = parse_object_path(SESSION_PATH)?; + let seat_path = parse_object_path(SEAT_PATH)?; + let user_path = parse_object_path(USER_PATH)?; - eprintln!("redbear-sessiond: starter address={:?}", env::var("DBUS_STARTER_ADDRESS").ok()); - eprintln!("redbear-sessiond: building D-Bus connection"); - let mut builder = system_connection_builder()?; - eprintln!("redbear-sessiond: builder created"); - builder = builder.name(BUS_NAME)?; - eprintln!("redbear-sessiond: bus name reserved"); - builder = builder.serve_at(MANAGER_PATH, manager)?; - eprintln!("redbear-sessiond: served manager path {MANAGER_PATH}"); - builder = builder.serve_at(SESSION_PATH, session)?; - eprintln!("redbear-sessiond: served session path {SESSION_PATH}"); - builder = builder.serve_at(SEAT_PATH, seat)?; - eprintln!("redbear-sessiond: served seat path {SEAT_PATH}"); - eprintln!("redbear-sessiond: finalizing connection build"); - let connection = builder.build().await?; + let session = LoginSession::new(seat_path.clone(), user_path, DeviceMap::new()); + let seat = LoginSeat::new(session_path.clone()); + let manager = LoginManager::new(session_path, seat_path); - eprintln!("redbear-sessiond: registered {BUS_NAME} on the system bus"); - - tokio::spawn(acpi_watcher::watch_and_emit(connection.clone())); - - wait_for_shutdown().await?; - eprintln!("redbear-sessiond: received shutdown signal, exiting cleanly"); - - Ok(()) + match system_connection_builder()? + .name(BUS_NAME)? + .serve_at(MANAGER_PATH, manager)? + .serve_at(SESSION_PATH, session)? + .serve_at(SEAT_PATH, seat)? + .build() + .await + { + Ok(connection) => { + eprintln!("redbear-sessiond: registered {BUS_NAME} on the system bus"); + tokio::spawn(acpi_watcher::watch_and_emit(connection.clone())); + wait_for_shutdown().await?; + drop(connection); + return Ok(()); + } + Err(err) => { + if attempt < 5 { + eprintln!("redbear-sessiond: attempt {attempt}/5 failed ({err}), retrying in 2s..."); + tokio::time::sleep(Duration::from_secs(2)).await; + } + last_err = Some(err.into()); + } + } + } + Err(last_err.unwrap()) } fn main() { diff --git a/local/recipes/system/redbear-udisks/source/src/inventory.rs b/local/recipes/system/redbear-udisks/source/src/inventory.rs index f3fd8519..ea734276 100644 --- a/local/recipes/system/redbear-udisks/source/src/inventory.rs +++ b/local/recipes/system/redbear-udisks/source/src/inventory.rs @@ -101,9 +101,7 @@ impl Inventory { for (root_key, entry_name) in roots { let device_path = format!("{}/{entry_name}", scheme_path.display()); - let Some(metadata) = read_device_metadata(Path::new(&device_path)) else { - continue; - }; + let metadata = read_device_metadata(Path::new(&device_path)); let drive = DriveDevice { object_path: owned_object_path(&format!( @@ -111,7 +109,7 @@ impl Inventory { stable_object_name(&scheme_name, &entry_name) )), scheme_identity: scheme_identity.clone(), - size: metadata.size, + size: metadata.as_ref().map_or(0, |m| m.size), }; drive_paths.insert(root_key, drive.object_path.clone()); @@ -123,9 +121,9 @@ impl Inventory { )), drive_object_path: drive.object_path.clone(), device_path, - size: metadata.size, - logical_block_size: metadata.logical_block_size, - read_only: metadata.read_only, + size: metadata.as_ref().map_or(0, |m| m.size), + logical_block_size: metadata.as_ref().map_or(0, |m| m.logical_block_size), + read_only: metadata.as_ref().map_or(false, |m| m.read_only), hint_partitionable: true, }); @@ -141,9 +139,7 @@ impl Inventory { }; let device_path = format!("{}/{entry_name}", scheme_path.display()); - let Some(metadata) = read_device_metadata(Path::new(&device_path)) else { - continue; - }; + let metadata = read_device_metadata(Path::new(&device_path)); blocks.push(BlockDevice { object_path: owned_object_path(&format!( @@ -152,9 +148,9 @@ impl Inventory { )), drive_object_path: drive_object_path.clone(), device_path, - size: metadata.size, - logical_block_size: metadata.logical_block_size, - read_only: metadata.read_only, + size: metadata.as_ref().map_or(0, |m| m.size), + logical_block_size: metadata.as_ref().map_or(0, |m| m.logical_block_size), + read_only: metadata.as_ref().map_or(false, |m| m.read_only), hint_partitionable: false, }); } diff --git a/local/recipes/system/redbear-udisks/source/src/main.rs b/local/recipes/system/redbear-udisks/source/src/main.rs index 28e23291..d70a5c1a 100644 --- a/local/recipes/system/redbear-udisks/source/src/main.rs +++ b/local/recipes/system/redbear-udisks/source/src/main.rs @@ -4,8 +4,11 @@ mod inventory; use std::{ env, error::Error, + path::Path, process, sync::Arc, + thread, + time::Duration, }; use interfaces::{BlockDeviceInterface, DriveInterface, ObjectManagerRoot, UDisksManager}; @@ -28,6 +31,21 @@ fn usage() -> &'static str { "Usage: redbear-udisks [--help]" } +async fn wait_for_dbus_socket() { + let socket_path = env::var("DBUS_STARTER_ADDRESS") + .ok() + .and_then(|addr| addr.strip_prefix("unix:path=").map(String::from)) + .unwrap_or_else(|| "/run/dbus/system_bus_socket".to_string()); + + for _ in 0..30 { + if tokio::net::UnixStream::connect(&socket_path).await.is_ok() { + return; + } + tokio::time::sleep(Duration::from_secs(1)).await; + } + eprintln!("redbear-udisks: timed out waiting for D-Bus socket at {socket_path}"); +} + fn parse_args() -> Result { let mut args = env::args().skip(1); @@ -82,51 +100,48 @@ async fn wait_for_shutdown() -> Result<(), Box> { } async fn run_daemon() -> Result<(), Box> { - eprintln!("redbear-udisks: startup begin"); - let _root_path = parse_object_path(ROOT_PATH)?; - let _manager_path = parse_object_path(MANAGER_PATH)?; - eprintln!("redbear-udisks: object paths parsed"); - let inventory = Arc::new(Inventory::scan()); - eprintln!( - "redbear-udisks: inventory scanned drives={} blocks={}", - inventory.drives().len(), - inventory.blocks().len() - ); - let block_sizes_known = inventory - .blocks() - .iter() - .filter(|block| block.logical_block_size > 0) - .count(); + wait_for_dbus_socket().await; - eprintln!("redbear-udisks: starter address={:?}", env::var("DBUS_STARTER_ADDRESS").ok()); - eprintln!("redbear-udisks: building D-Bus connection"); - let mut builder = system_connection_builder()? - .name(BUS_NAME)? - .serve_at(ROOT_PATH, ObjectManagerRoot::new(inventory.clone()))? - .serve_at(MANAGER_PATH, UDisksManager::new(inventory.clone()))?; + let mut last_err = None; + for attempt in 1..=5 { + let _root_path = parse_object_path(ROOT_PATH)?; + let _manager_path = parse_object_path(MANAGER_PATH)?; + let inventory = Arc::new(Inventory::scan()); - for drive in inventory.drives() { - builder = builder.serve_at(drive.object_path.as_str(), DriveInterface::new(drive.clone()))?; + let mut builder = system_connection_builder()? + .name(BUS_NAME)? + .serve_at(ROOT_PATH, ObjectManagerRoot::new(inventory.clone()))? + .serve_at(MANAGER_PATH, UDisksManager::new(inventory.clone()))?; + + for drive in inventory.drives() { + builder = builder.serve_at(drive.object_path.as_str(), DriveInterface::new(drive.clone()))?; + } + + for block in inventory.blocks() { + builder = builder.serve_at(block.object_path.as_str(), BlockDeviceInterface::new(block.clone()))?; + } + + match builder.build().await { + Ok(connection) => { + eprintln!( + "redbear-udisks: registered {BUS_NAME} on the system bus ({} drives, {} blocks)", + inventory.drives().len(), + inventory.blocks().len(), + ); + wait_for_shutdown().await?; + drop(connection); + return Ok(()); + } + Err(err) => { + if attempt < 5 { + eprintln!("redbear-udisks: attempt {attempt}/5 failed ({err}), retrying in 2s..."); + tokio::time::sleep(Duration::from_secs(2)).await; + } + last_err = Some(err.into()); + } + } } - - for block in inventory.blocks() { - builder = builder.serve_at(block.object_path.as_str(), BlockDeviceInterface::new(block.clone()))?; - } - - let connection = builder.build().await?; - - eprintln!( - "redbear-udisks: registered {BUS_NAME} on the system bus with {} drives, {} block devices, {} metadata-backed block sizes", - inventory.drives().len(), - inventory.blocks().len(), - block_sizes_known, - ); - - wait_for_shutdown().await?; - drop(connection); - eprintln!("redbear-udisks: received shutdown signal, exiting cleanly"); - - Ok(()) + Err(last_err.unwrap()) } fn main() { diff --git a/local/recipes/system/redbear-upower/source/src/main.rs b/local/recipes/system/redbear-upower/source/src/main.rs index 106e6a77..1d7d0564 100644 --- a/local/recipes/system/redbear-upower/source/src/main.rs +++ b/local/recipes/system/redbear-upower/source/src/main.rs @@ -4,6 +4,8 @@ use std::{ fs, path::{Path, PathBuf}, process, + thread, + time::Duration, }; use tokio::runtime::Builder as RuntimeBuilder; @@ -102,6 +104,21 @@ fn parse_args() -> Result { } } +async fn wait_for_dbus_socket() { + let socket_path = env::var("DBUS_STARTER_ADDRESS") + .ok() + .and_then(|addr| addr.strip_prefix("unix:path=").map(String::from)) + .unwrap_or_else(|| "/run/dbus/system_bus_socket".to_string()); + + for _ in 0..30 { + if tokio::net::UnixStream::connect(&socket_path).await.is_ok() { + return; + } + tokio::time::sleep(Duration::from_secs(1)).await; + } + eprintln!("redbear-upower: timed out waiting for D-Bus socket at {socket_path}"); +} + fn parse_object_path(path: &str) -> Result> { Ok(OwnedObjectPath::try_from(path.to_owned())?) } @@ -453,70 +470,65 @@ impl PowerDevice { } async fn run_daemon() -> Result<(), Box> { - eprintln!("redbear-upower: startup begin"); + wait_for_dbus_socket().await; let runtime = PowerRuntime::discover()?; - eprintln!( - "redbear-upower: runtime discovered adapters={} batteries={}", - runtime.adapter_ids.len(), - runtime.battery_ids.len() - ); let _display_device_path = parse_object_path(DISPLAY_DEVICE_PATH)?; - eprintln!("redbear-upower: object paths parsed"); - eprintln!("redbear-upower: starter address={:?}", env::var("DBUS_STARTER_ADDRESS").ok()); - eprintln!("redbear-upower: building D-Bus connection"); - let mut builder = system_connection_builder()?; - eprintln!("redbear-upower: builder created"); - builder = builder.name(BUS_NAME)?; - eprintln!("redbear-upower: bus name reserved"); - builder = builder.serve_at( - UPOWER_PATH, - UPowerDaemon { - runtime: runtime.clone(), - }, - )?; - eprintln!("redbear-upower: served manager path {UPOWER_PATH}"); - builder = builder.serve_at( - DISPLAY_DEVICE_PATH, - DisplayDevice { - runtime: runtime.clone(), - }, - )?; - eprintln!("redbear-upower: served display device path {DISPLAY_DEVICE_PATH}"); + let mut last_err = None; + for attempt in 1..=5 { + let mut builder = system_connection_builder()? + .name(BUS_NAME)? + .serve_at( + UPOWER_PATH, + UPowerDaemon { + runtime: runtime.clone(), + }, + )? + .serve_at( + DISPLAY_DEVICE_PATH, + DisplayDevice { + runtime: runtime.clone(), + }, + )?; - for adapter_id in &runtime.adapter_ids { - let path = format!("/org/freedesktop/UPower/devices/line_power_{adapter_id}"); - eprintln!("redbear-upower: serving adapter path {path}"); - builder = builder.serve_at( - path, - PowerDevice { - runtime: runtime.clone(), - descriptor: DeviceDescriptor::Adapter(adapter_id.clone()), - }, - )?; + for adapter_id in &runtime.adapter_ids { + let path = format!("/org/freedesktop/UPower/devices/line_power_{adapter_id}"); + builder = builder.serve_at( + path, + PowerDevice { + runtime: runtime.clone(), + descriptor: DeviceDescriptor::Adapter(adapter_id.clone()), + }, + )?; + } + for battery_id in &runtime.battery_ids { + let path = format!("/org/freedesktop/UPower/devices/battery_{battery_id}"); + builder = builder.serve_at( + path, + PowerDevice { + runtime: runtime.clone(), + descriptor: DeviceDescriptor::Battery(battery_id.clone()), + }, + )?; + } + + match builder.build().await { + Ok(connection) => { + eprintln!("redbear-upower: registered {BUS_NAME} on the system bus"); + wait_for_shutdown().await?; + drop(connection); + return Ok(()); + } + Err(err) => { + if attempt < 5 { + eprintln!("redbear-upower: attempt {attempt}/5 failed ({err}), retrying in 2s..."); + tokio::time::sleep(Duration::from_secs(2)).await; + } + last_err = Some(err.into()); + } + } } - for battery_id in &runtime.battery_ids { - let path = format!("/org/freedesktop/UPower/devices/battery_{battery_id}"); - eprintln!("redbear-upower: serving battery path {path}"); - builder = builder.serve_at( - path, - PowerDevice { - runtime: runtime.clone(), - descriptor: DeviceDescriptor::Battery(battery_id.clone()), - }, - )?; - } - - eprintln!("redbear-upower: finalizing connection build"); - let connection = builder.build().await?; - - eprintln!("redbear-upower: registered {BUS_NAME} on the system bus"); - - wait_for_shutdown().await?; - drop(connection); - eprintln!("redbear-upower: received shutdown signal, exiting cleanly"); - - Ok(()) + Err(last_err.unwrap()) } fn main() {