use itertools::Itertools; use log::{info, warn}; use std::collections::BTreeSet as Set; use std::process::Command; use super::{format_err, retry_or_ignore, Config, Result}; use crate::{ udev, utils::{select_n_by_regex, NameAliases}, }; pub fn setup(cfg: &Config) -> Result<()> { if cfg.networks.is_empty() { warn!("no networks configured"); return Ok(()); } let mut assigned: Set = Set::new(); for net in &cfg.networks { retry_or_ignore(|| { info!("setting up network {}", net.name); let netdevs = get_interfaces()? .filter(|dev| !assigned.contains(dev.name())) .collect::>(); for dev in &netdevs { info!( "- available network device: {}, aliases [{}]", dev.name(), dev.aliases().join(", ") ); } let mut cmd = Command::new("ash"); cmd.arg("-c"); cmd.arg(&net.script); let mut selected = Vec::new(); for iface in &net.interfaces { let var = &iface.var; let netdevs = netdevs.iter().filter(|na| !assigned.contains(na.name())); let if_names = select_n_by_regex(iface.n, &iface.regexps, netdevs); if if_names.is_empty() { return Err(format_err!("- no interface match for {var:?}")); } let value = if_names.join(" "); info!("- {var}={value}"); cmd.env(var, value); selected.extend(if_names); } info!("- running script"); let status = cmd.status()?; if !status.success() { return Err(format_err!("setup script failed: {status}")); } assigned.extend(selected); Ok(()) }); } Ok(()) } fn get_interfaces() -> Result> { Ok(udev::get_devices("net")?.into_iter().map(|dev| { let mut na = NameAliases::new(dev.sysname().to_string()); for (property, value) in dev.properties() { if [ "INTERFACE", "ID_NET_NAME", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC", "ID_NET_NAME_SLOT", ] .contains(&property) { na.push(value.to_string()); } } na })) }