wifi: Properly parse all NM config files for backend

Previously there was a half-baked parser that looked for a fixed value in a
fixed place, but this was not robust. This approach is properly robust, in case
various different files set or override it.
This commit is contained in:
Vicki Pfau 2024-08-29 20:12:43 -07:00
parent 6c485684b8
commit 4c81c92586
3 changed files with 110 additions and 24 deletions

73
Cargo.lock generated
View file

@ -306,10 +306,31 @@ dependencies = [
"lazy_static",
"nom",
"pathdiff",
"rust-ini",
"serde",
"toml",
]
[[package]]
name = "const-random"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
dependencies = [
"const-random-macro",
]
[[package]]
name = "const-random-macro"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
dependencies = [
"getrandom",
"once_cell",
"tiny-keccak",
]
[[package]]
name = "cpufeatures"
version = "0.2.12"
@ -325,6 +346,12 @@ version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-common"
version = "0.1.6"
@ -345,6 +372,15 @@ dependencies = [
"crypto-common",
]
[[package]]
name = "dlv-list"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
dependencies = [
"const-random",
]
[[package]]
name = "either"
version = "1.13.0"
@ -499,6 +535,12 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
[[package]]
name = "hashbrown"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
[[package]]
name = "hashbrown"
version = "0.14.5"
@ -536,7 +578,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown",
"hashbrown 0.14.5",
]
[[package]]
@ -698,6 +740,16 @@ version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "ordered-multimap"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e"
dependencies = [
"dlv-list",
"hashbrown 0.13.2",
]
[[package]]
name = "ordered-stream"
version = "0.2.0"
@ -885,6 +937,16 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "rust-ini"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091"
dependencies = [
"cfg-if",
"ordered-multimap",
]
[[package]]
name = "rustc-demangle"
version = "0.1.24"
@ -1088,6 +1150,15 @@ dependencies = [
"once_cell",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "tokio"
version = "1.39.2"

View file

@ -13,7 +13,7 @@ strip="symbols"
anyhow = "1"
async-trait = "0.1"
clap = { version = "4.5", default-features = false, features = ["derive", "help", "std", "usage"] }
config = { version = "0.14", default-features = false, features = ["async", "toml"] }
config = { version = "0.14", default-features = false, features = ["async", "ini", "toml"] }
inotify = { version = "0.10", default-features = false, features = ["stream"] }
lazy_static = "1"
libc = "0.2"

View file

@ -6,15 +6,17 @@
*/
use anyhow::{anyhow, bail, ensure, Error, Result};
use config::builder::AsyncState;
use config::{ConfigBuilder, FileFormat};
use std::str::FromStr;
use strum::{Display, EnumString};
use tokio::fs;
use tracing::error;
use zbus::Connection;
use crate::path;
use crate::process::{run_script, script_output};
use crate::systemd::{daemon_reload, SystemdUnit};
use crate::{path, read_config_directory};
const OVERRIDE_CONTENTS: &str = "[Service]
ExecStart=
@ -30,7 +32,10 @@ const TRACE_CMD_PATH: &str = "/usr/bin/trace-cmd";
const MIN_BUFFER_SIZE: u32 = 100;
const WIFI_BACKEND_PATH: &str = "/etc/NetworkManager/conf.d/99-valve-wifi-backend.conf";
const WIFI_BACKEND_PATHS: &[&str] = &[
"/usr/lib/etc/NetworkManager/conf.d",
"/etc/NetworkManager/conf.d",
];
#[derive(Display, EnumString, PartialEq, Debug, Copy, Clone)]
#[strum(serialize_all = "snake_case", ascii_case_insensitive)]
@ -209,15 +214,19 @@ pub(crate) async fn set_wifi_debug_mode(
}
pub(crate) async fn get_wifi_backend() -> Result<WifiBackend> {
let wifi_backend_contents = fs::read_to_string(path(WIFI_BACKEND_PATH))
.await?
.trim()
.to_string();
for line in wifi_backend_contents.lines() {
if line.starts_with("wifi.backend=") {
let backend = line.trim_start_matches("wifi.backend=").trim();
return Ok(WifiBackend::from_str(backend)?);
let mut builder = ConfigBuilder::<AsyncState>::default();
for dir in WIFI_BACKEND_PATHS {
println!("{dir}");
builder = read_config_directory(builder, path(dir), &["conf"], FileFormat::Ini).await?;
}
println!("{builder:?}");
let config = builder.build().await?;
println!("{config:?}");
if let Some(backend) = config.get_table("device")?.remove("wifi.backend") {
let backend = backend.into_string()?;
println!("{backend:?}");
return Ok(WifiBackend::from_str(backend.as_str())?);
}
bail!("Wi-Fi backend not found in config");
@ -330,29 +339,35 @@ mod test {
async fn test_get_wifi_backend() {
let _h = testing::start();
create_dir_all(path(WIFI_BACKEND_PATH).parent().unwrap())
.await
.expect("create_dir_all");
for dir in WIFI_BACKEND_PATHS {
create_dir_all(path(dir)).await.expect("create_dir_all");
}
assert!(get_wifi_backend().await.is_err());
write(path(WIFI_BACKEND_PATH), "[device]")
write(path(WIFI_BACKEND_PATHS[0]).join("test.conf"), "[device]")
.await
.expect("write");
assert!(get_wifi_backend().await.is_err());
write(path(WIFI_BACKEND_PATH), "[device]\nwifi.backend=fake\n")
write(
path(WIFI_BACKEND_PATHS[0]).join("test.conf"),
"[device]\nwifi.backend=fake\n",
)
.await
.expect("write");
assert!(get_wifi_backend().await.is_err());
write(path(WIFI_BACKEND_PATH), "[device]\nwifi.backend=iwd\n")
write(
path(WIFI_BACKEND_PATHS[0]).join("test.conf"),
"[device]\nwifi.backend=iwd\n",
)
.await
.expect("write");
assert_eq!(get_wifi_backend().await.unwrap(), WifiBackend::Iwd);
write(
path(WIFI_BACKEND_PATH),
path(WIFI_BACKEND_PATHS[0]).join("test.conf"),
"[device]\nwifi.backend=wpa_supplicant\n",
)
.await