* fix: use FHS-compliant /var/lib/numa as Linux data dir default numa's default system-wide data directory was hardcoded to /usr/local/var/numa for all Unix platforms. This is the right path on macOS (Homebrew prefix convention) but non-FHS on Linux, where Arch / Fedora / Debian / etc. expect persistent state under /var/lib/<pkg>. The mismatch was invisible to existing users (numa creates the dir silently on first run) but immediately surfaces when packaging for a distro — see PR #33 (community contribution to add an Arch AUR package) which had to add fragile sed-based path patching at PKGBUILD build time. The fix moves the path decision into a small helper: - daemon_data_dir() — cfg-gated platform dispatch (linux/macos) - resolve_linux_data_dir() — pure function, takes "does X exist?" as parameters, returns the right path Linux behavior: - Fresh install → /var/lib/numa (FHS) - Upgrading from pre-v0.10.1 install → /usr/local/var/numa (legacy) - Both paths exist → /var/lib/numa (FHS wins) The legacy fallback is critical: existing v0.10.0 Linux users have their CA cert + services.json under /usr/local/var/numa. Returning the new path unconditionally would cause CA regeneration on upgrade, breaking every browser that had trusted the previous CA. The fallback is checked at startup via std::path::Path::exists, so the upgrade is seamless and zero-config. macOS behavior is unchanged — /usr/local/var/numa is still correct because Homebrew's prefix is /usr/local. Test coverage: - resolve_linux_data_dir is a pure function gated cfg(any(linux,test)) so the same code path is unit-tested on every platform's CI run. - Four tests cover all combinations of (legacy_exists, fhs_exists), asserting the migration logic stays correct under future edits. The default config in numa.toml is also updated to document the new per-platform default paths. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: end-to-end FHS path verification + simplify cleanup Two related changes from a /simplify pass and a follow-up testing finalization: 1. lib.rs cleanup (no behavior change): - Drop FHS_LINUX_DATA_DIR and LEGACY_LINUX_DATA_DIR consts. Both were used in only 4 places total and the unit tests already bypassed them with string literals, so they were over-engineering. Inline the strings in daemon_data_dir() and resolve_linux_data_dir(). - Trim narrating doc/comments on the helper and the test bodies. Keep only the non-obvious WHY (the macOS Homebrew note and the migration-keeps-legacy rationale). 2. tests/docker/smoke-arch.sh: - Cherry-picked the previously-uncommitted Arch compatibility smoke test from feat/smoke-arch. - Removed the [server] data_dir = "/tmp/numa-smoke" override from the test config so the script now exercises the DEFAULT data dir code path — which is exactly what the FHS fix touches. - Added a path assertion after the dig succeeds: verify that /var/lib/numa/ca.pem exists (FHS) and /usr/local/var/numa is absent (no accidental dual-creation on a fresh install). Verified end-to-end on archlinux:latest (Apple Silicon, Rosetta): ── building + running numa on archlinux:latest ── ── cargo build --release --locked ── Finished `release` profile [optimized] target(s) in 24.02s ── dig @127.0.0.1 -p 5354 google.com A ── 142.251.38.206 ── FHS path check ── ✓ CA cert at /var/lib/numa/ca.pem (FHS path) ✓ legacy path /usr/local/var/numa absent (fresh install used FHS) ── smoke-arch passed ── This closes the testing gap where the unit tests covered the path-decision LOGIC in isolation but nothing exercised the live wiring on a real Linux filesystem. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
148 lines
4.3 KiB
Rust
148 lines
4.3 KiB
Rust
pub mod api;
|
|
pub mod blocklist;
|
|
pub mod buffer;
|
|
pub mod cache;
|
|
pub mod config;
|
|
pub mod ctx;
|
|
pub mod dnssec;
|
|
pub mod dot;
|
|
pub mod forward;
|
|
pub mod header;
|
|
pub mod lan;
|
|
pub mod override_store;
|
|
pub mod packet;
|
|
pub mod proxy;
|
|
pub mod query_log;
|
|
pub mod question;
|
|
pub mod record;
|
|
pub mod recursive;
|
|
pub mod service_store;
|
|
pub mod srtt;
|
|
pub mod stats;
|
|
pub mod system_dns;
|
|
pub mod tls;
|
|
|
|
pub type Error = Box<dyn std::error::Error + Send + Sync>;
|
|
pub type Result<T> = std::result::Result<T, Error>;
|
|
|
|
/// Shared config directory for persistent data (services.json, etc).
|
|
/// Unix users: ~/.config/numa/
|
|
/// Linux root daemon: /var/lib/numa (FHS) — falls back to /usr/local/var/numa
|
|
/// if a pre-v0.10.1 install already lives there.
|
|
/// macOS root daemon: /usr/local/var/numa (Homebrew prefix)
|
|
/// Windows: %APPDATA%\numa
|
|
pub fn config_dir() -> std::path::PathBuf {
|
|
#[cfg(windows)]
|
|
{
|
|
std::path::PathBuf::from(
|
|
std::env::var("APPDATA").unwrap_or_else(|_| "C:\\ProgramData".into()),
|
|
)
|
|
.join("numa")
|
|
}
|
|
#[cfg(not(windows))]
|
|
{
|
|
config_dir_unix()
|
|
}
|
|
}
|
|
|
|
#[cfg(not(windows))]
|
|
fn config_dir_unix() -> std::path::PathBuf {
|
|
// When run via sudo, SUDO_USER has the real user
|
|
if let Ok(user) = std::env::var("SUDO_USER") {
|
|
let home = if cfg!(target_os = "macos") {
|
|
format!("/Users/{}", user)
|
|
} else {
|
|
format!("/home/{}", user)
|
|
};
|
|
return std::path::PathBuf::from(home).join(".config").join("numa");
|
|
}
|
|
|
|
// Normal user (not root)
|
|
if let Ok(home) = std::env::var("HOME") {
|
|
let path = std::path::PathBuf::from(&home);
|
|
if !home.starts_with("/var/root") && !home.starts_with("/root") {
|
|
return path.join(".config").join("numa");
|
|
}
|
|
}
|
|
|
|
// Running as root daemon (launchd/systemd) — use system-wide path
|
|
daemon_data_dir()
|
|
}
|
|
|
|
/// Default system-wide data directory for TLS certs. Overridable via
|
|
/// `[server] data_dir = "..."` in numa.toml — this function only provides
|
|
/// the fallback when the config doesn't set it.
|
|
/// Linux: /var/lib/numa (FHS) — falls back to /usr/local/var/numa if a
|
|
/// pre-v0.10.1 install already has data there.
|
|
/// macOS: /usr/local/var/numa (Homebrew prefix)
|
|
/// Windows: %PROGRAMDATA%\numa
|
|
pub fn data_dir() -> std::path::PathBuf {
|
|
#[cfg(windows)]
|
|
{
|
|
std::path::PathBuf::from(
|
|
std::env::var("PROGRAMDATA").unwrap_or_else(|_| "C:\\ProgramData".into()),
|
|
)
|
|
.join("numa")
|
|
}
|
|
#[cfg(not(windows))]
|
|
{
|
|
daemon_data_dir()
|
|
}
|
|
}
|
|
|
|
/// Resolve the system-wide data directory for the running platform.
|
|
/// Honors backwards compatibility with pre-v0.10.1 installs that still
|
|
/// have their CA cert + services.json under `/usr/local/var/numa`.
|
|
#[cfg(not(windows))]
|
|
fn daemon_data_dir() -> std::path::PathBuf {
|
|
#[cfg(target_os = "linux")]
|
|
{
|
|
std::path::PathBuf::from(resolve_linux_data_dir(
|
|
std::path::Path::new("/usr/local/var/numa").exists(),
|
|
std::path::Path::new("/var/lib/numa").exists(),
|
|
))
|
|
}
|
|
#[cfg(target_os = "macos")]
|
|
{
|
|
// macOS uses the Homebrew prefix convention; no FHS migration needed.
|
|
std::path::PathBuf::from("/usr/local/var/numa")
|
|
}
|
|
}
|
|
|
|
/// Extracted as a pure function so the migration logic is unit-testable
|
|
/// without touching the real filesystem.
|
|
#[cfg(any(target_os = "linux", test))]
|
|
fn resolve_linux_data_dir(legacy_exists: bool, fhs_exists: bool) -> &'static str {
|
|
if legacy_exists && !fhs_exists {
|
|
"/usr/local/var/numa"
|
|
} else {
|
|
"/var/lib/numa"
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn linux_data_dir_fresh_install_uses_fhs() {
|
|
assert_eq!(resolve_linux_data_dir(false, false), "/var/lib/numa");
|
|
}
|
|
|
|
#[test]
|
|
fn linux_data_dir_upgrading_install_keeps_legacy() {
|
|
// Migration must keep legacy so the user doesn't lose their CA on upgrade.
|
|
assert_eq!(resolve_linux_data_dir(true, false), "/usr/local/var/numa");
|
|
}
|
|
|
|
#[test]
|
|
fn linux_data_dir_after_migration_uses_fhs() {
|
|
assert_eq!(resolve_linux_data_dir(true, true), "/var/lib/numa");
|
|
}
|
|
|
|
#[test]
|
|
fn linux_data_dir_only_fhs_uses_fhs() {
|
|
assert_eq!(resolve_linux_data_dir(false, true), "/var/lib/numa");
|
|
}
|
|
}
|