diff --git a/src/config/types.rs b/src/config/types.rs index e523592..04a22ce 100644 --- a/src/config/types.rs +++ b/src/config/types.rs @@ -3,6 +3,7 @@ use ipnetwork::IpNetwork; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::net::IpAddr; +use std::path::PathBuf; use super::defaults::*; @@ -356,6 +357,9 @@ impl Default for NetworkConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct GeneralConfig { + #[serde(default)] + pub data_path: Option, + #[serde(default)] pub modes: ProxyModes, @@ -871,6 +875,7 @@ pub struct GeneralConfig { impl Default for GeneralConfig { fn default() -> Self { Self { + data_path: None, modes: ProxyModes::default(), prefer_ipv6: false, fast_mode: default_true(), diff --git a/src/maestro/helpers.rs b/src/maestro/helpers.rs index acaecdd..78f3ec4 100644 --- a/src/maestro/helpers.rs +++ b/src/maestro/helpers.rs @@ -1,4 +1,5 @@ use std::time::Duration; +use std::path::PathBuf; use tokio::sync::watch; use tracing::{debug, error, info, warn}; @@ -9,8 +10,9 @@ use crate::transport::middle_proxy::{ ProxyConfigData, fetch_proxy_config_with_raw, load_proxy_config_cache, save_proxy_config_cache, }; -pub(crate) fn parse_cli() -> (String, bool, Option) { +pub(crate) fn parse_cli() -> (String, Option, bool, Option) { let mut config_path = "config.toml".to_string(); + let mut data_path: Option = None; let mut silent = false; let mut log_level: Option = None; @@ -28,6 +30,18 @@ pub(crate) fn parse_cli() -> (String, bool, Option) { let mut i = 0; while i < args.len() { match args[i].as_str() { + "--data-path" => { + i += 1; + if i < args.len() { + data_path = Some(PathBuf::from(args[i].clone())); + } else { + eprintln!("Missing value for --data-path"); + std::process::exit(0); + } + } + s if s.starts_with("--data-path=") => { + data_path = Some(PathBuf::from(s.trim_start_matches("--data-path=").to_string())); + } "--silent" | "-s" => { silent = true; } @@ -44,6 +58,7 @@ pub(crate) fn parse_cli() -> (String, bool, Option) { eprintln!("Usage: telemt [config.toml] [OPTIONS]"); eprintln!(); eprintln!("Options:"); + eprintln!(" --data-path Set data directory (absolute path; overrides config value)"); eprintln!(" --silent, -s Suppress info logs"); eprintln!(" --log-level debug|verbose|normal|silent"); eprintln!(" --help, -h Show this help"); @@ -78,7 +93,7 @@ pub(crate) fn parse_cli() -> (String, bool, Option) { i += 1; } - (config_path, silent, log_level) + (config_path, data_path, silent, log_level) } pub(crate) fn print_proxy_links(host: &str, port: u16, config: &ProxyConfig) { diff --git a/src/maestro/mod.rs b/src/maestro/mod.rs index 3db7f02..047c204 100644 --- a/src/maestro/mod.rs +++ b/src/maestro/mod.rs @@ -58,7 +58,7 @@ pub async fn run() -> std::result::Result<(), Box> { startup_tracker .start_component(COMPONENT_CONFIG_LOAD, Some("load and validate config".to_string())) .await; - let (config_path, cli_silent, cli_log_level) = parse_cli(); + let (config_path, data_path, cli_silent, cli_log_level) = parse_cli(); let mut config = match ProxyConfig::load(&config_path) { Ok(c) => c, @@ -80,6 +80,34 @@ pub async fn run() -> std::result::Result<(), Box> { std::process::exit(1); } + if let Some(p) = data_path { + config.general.data_path = Some(p); + } + + if let Some(ref data_path) = config.general.data_path { + if !data_path.is_absolute() { + eprintln!("[telemt] data_path must be absolute: {}", data_path.display()); + std::process::exit(1); + } + + if data_path.exists() { + if !data_path.is_dir() { + eprintln!("[telemt] data_path exists but is not a directory: {}", data_path.display()); + std::process::exit(1); + } + } else { + if let Err(e) = std::fs::create_dir_all(data_path) { + eprintln!("[telemt] Can't create data_path {}: {}", data_path.display(), e); + std::process::exit(1); + } + } + + if let Err(e) = std::env::set_current_dir(data_path) { + eprintln!("[telemt] Can't use data_path {}: {}", data_path.display(), e); + std::process::exit(1); + } + } + if let Err(e) = crate::network::dns_overrides::install_entries(&config.network.dns_overrides) { eprintln!("[telemt] Invalid network.dns_overrides: {}", e); std::process::exit(1);