ant_node_manager/
config.rs

1// Copyright (C) 2024 MaidSafe.net limited.
2//
3// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
4// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
5// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
6// KIND, either express or implied. Please review the Licences for the specific language governing
7// permissions and limitations relating to use of the SAFE Network Software.
8
9use ant_releases::ReleaseType;
10use color_eyre::{eyre::eyre, Result};
11use std::path::PathBuf;
12
13#[cfg(unix)]
14pub fn get_daemon_install_path() -> PathBuf {
15    PathBuf::from("/usr/local/bin/antctld")
16}
17
18#[cfg(windows)]
19pub fn get_daemon_install_path() -> PathBuf {
20    PathBuf::from("C:\\ProgramData\\antctld\\antctld.exe")
21}
22
23#[cfg(unix)]
24pub fn get_node_manager_path() -> Result<PathBuf> {
25    // This needs to be a system-wide location rather than a user directory because the `install`
26    // command will run as the root user. However, it should be readable by non-root users, because
27    // other commands, e.g., requesting status, shouldn't require root.
28    use std::os::unix::fs::PermissionsExt;
29
30    let path = if is_running_as_root() {
31        debug!("Running as root");
32        let path = PathBuf::from("/var/antctl/");
33        debug!("Creating antctl directory: {path:?}");
34        std::fs::create_dir_all(&path)?;
35        let mut perm = std::fs::metadata(&path)?.permissions();
36        perm.set_mode(0o755); // set permissions to rwxr-xr-x
37        std::fs::set_permissions(&path, perm)?;
38        path
39    } else {
40        debug!("Running as non-root");
41        let path = get_user_antnode_data_dir()?;
42        debug!("antctl path: {path:?}");
43        path
44    };
45
46    if is_running_as_root() && !path.exists() {
47        std::fs::create_dir_all(&path)?;
48        let mut perm = std::fs::metadata(&path)?.permissions();
49        perm.set_mode(0o755); // set permissions to rwxr-xr-x
50        std::fs::set_permissions(&path, perm)?;
51    }
52
53    Ok(path)
54}
55
56#[cfg(windows)]
57pub fn get_node_manager_path() -> Result<PathBuf> {
58    use std::path::Path;
59    let path = Path::new("C:\\ProgramData\\antctl");
60    debug!("Running as root, creating node_manager_path at: {path:?}");
61
62    if !path.exists() {
63        std::fs::create_dir_all(path)?;
64    }
65    Ok(path.to_path_buf())
66}
67
68#[cfg(unix)]
69pub fn get_node_registry_path() -> Result<PathBuf> {
70    use std::os::unix::fs::PermissionsExt;
71
72    let path = get_node_manager_path()?;
73    let node_registry_path = path.join("node_registry.json");
74    if is_running_as_root() && !node_registry_path.exists() {
75        debug!("Running as root");
76        debug!("Creating node registry path: {node_registry_path:?}");
77        std::fs::OpenOptions::new()
78            .write(true)
79            .create(true)
80            .truncate(true) // Do not append to the file if it already exists.
81            .open(node_registry_path.clone())?;
82        // Set the permissions of /var/antctl/node_registry.json to rwxrwxrwx. The
83        // `status` command updates the registry with the latest information it has on the
84        // services at the time it runs. It's normally the case that service management status
85        // operations do not require elevated privileges. If we want that to be the case, we
86        // need to give all users the ability to write to the registry file. Everything else in
87        // the /var/antctl directory and its subdirectories will still require elevated privileges.
88        let mut perm = std::fs::metadata(node_registry_path.clone())?.permissions();
89        perm.set_mode(0o777);
90        std::fs::set_permissions(node_registry_path.clone(), perm)?;
91    }
92    debug!("Node registry path: {node_registry_path:?}");
93
94    Ok(node_registry_path)
95}
96
97#[cfg(windows)]
98pub fn get_node_registry_path() -> Result<PathBuf> {
99    use std::path::Path;
100    let path = Path::new("C:\\ProgramData\\antctl");
101    if !path.exists() {
102        std::fs::create_dir_all(path)?;
103    }
104    debug!("Node registry path is: {path:?}");
105
106    Ok(path.join("node_registry.json"))
107}
108
109/// Get the data directory for the service.
110///
111/// It's a little counter-intuitive, but the owner will be `None` in the case of a user-mode
112/// service, because it will always run as the current user. The `owner` is really to specify the
113/// non-root user for running a system-wide service.
114#[cfg(unix)]
115pub fn get_service_data_dir_path(
116    custom_path: Option<PathBuf>,
117    owner: Option<String>,
118) -> Result<PathBuf> {
119    let path = match custom_path {
120        Some(p) => {
121            debug!("Using custom path for service data dir: {p:?}");
122            p
123        }
124        None => {
125            if owner.is_some() {
126                let path = PathBuf::from("/var/antctl/services");
127                debug!("Using default path for service data dir: {path:?}");
128                path
129            } else {
130                let path = get_user_antnode_data_dir()?;
131                debug!("Using user mode service data dir: {path:?}");
132                path
133            }
134        }
135    };
136    if let Some(owner) = owner {
137        create_owned_dir(path.clone(), &owner)?;
138    }
139    Ok(path)
140}
141
142#[cfg(windows)]
143pub fn get_service_data_dir_path(
144    custom_path: Option<PathBuf>,
145    _owner: Option<String>,
146) -> Result<PathBuf> {
147    let path = match custom_path {
148        Some(p) => {
149            debug!("Using custom path for service data dir: {p:?}");
150            p
151        }
152        None => {
153            let path = PathBuf::from("C:\\ProgramData\\antctl\\data");
154            debug!("Using default path for service data dir: {path:?}");
155            path
156        }
157    };
158    std::fs::create_dir_all(&path)?;
159    Ok(path)
160}
161
162/// Get the bootstrap cache owner path
163#[cfg(unix)]
164pub fn get_bootstrap_cache_owner_path(owner: &str) -> Result<PathBuf> {
165    let path = PathBuf::from("/var/antctl/bootstrap_cache");
166
167    create_owned_dir(path.clone(), owner)?;
168    Ok(path)
169}
170
171#[cfg(windows)]
172pub fn get_bootstrap_cache_owner_path(_owner: &str) -> Result<PathBuf> {
173    let path = PathBuf::from("C:\\ProgramData\\antctl\\bootstrap_cache");
174    std::fs::create_dir_all(&path)?;
175    Ok(path)
176}
177
178/// Get the logging directory for the service.
179///
180/// It's a little counter-intuitive, but the owner will be `None` in the case of a user-mode
181/// service, because it will always run as the current user. The `owner` is really to specify the
182/// non-root user for running a system-wide service.
183#[cfg(unix)]
184pub fn get_service_log_dir_path(
185    bin_type: ReleaseType,
186    custom_path: Option<PathBuf>,
187    owner: Option<String>,
188) -> Result<PathBuf> {
189    let path = match custom_path {
190        Some(p) => {
191            debug!("Using custom path for service log dir: {p:?}");
192            p
193        }
194        None => {
195            if owner.is_some() {
196                let path = PathBuf::from("/var/log").join(bin_type.to_string());
197                debug!("Using default path for service log dir: {path:?}");
198                path
199            } else {
200                let path = get_user_antnode_data_dir()?;
201                debug!("Using user mode service log dir: {path:?}");
202                path
203            }
204        }
205    };
206    if let Some(owner) = owner {
207        create_owned_dir(path.clone(), &owner)?;
208    }
209    Ok(path)
210}
211
212#[cfg(windows)]
213pub fn get_service_log_dir_path(
214    bin_type: ReleaseType,
215    custom_path: Option<PathBuf>,
216    _owner: Option<String>,
217) -> Result<PathBuf> {
218    let path = match custom_path {
219        Some(p) => {
220            debug!("Using custom path for service log dir: {p:?}");
221            p
222        }
223        None => {
224            let path = PathBuf::from("C:\\ProgramData")
225                .join(bin_type.to_string())
226                .join("logs");
227            debug!("Using default path for service log dir: {path:?}");
228            path
229        }
230    };
231    std::fs::create_dir_all(&path)?;
232    Ok(path)
233}
234
235#[cfg(unix)]
236pub fn create_owned_dir(path: PathBuf, owner: &str) -> Result<()> {
237    debug!("Creating owned dir and setting permissions: {path:?} with owner: {owner}");
238    use nix::unistd::{chown, Gid, Uid};
239    use std::os::unix::fs::PermissionsExt;
240    use users::get_user_by_name;
241
242    std::fs::create_dir_all(&path)?;
243    let permissions = std::fs::Permissions::from_mode(0o755);
244    std::fs::set_permissions(&path, permissions)?;
245
246    let user = get_user_by_name(owner).ok_or_else(|| {
247        error!("User '{owner}' does not exist");
248        eyre!("User '{owner}' does not exist")
249    })?;
250    let uid = Uid::from_raw(user.uid());
251    let gid = Gid::from_raw(user.primary_group_id());
252    chown(&path, Some(uid), Some(gid))?;
253    Ok(())
254}
255
256#[cfg(windows)]
257pub fn create_owned_dir(path: PathBuf, _owner: &str) -> Result<()> {
258    debug!("Creating owned dir: {path:?}");
259    std::fs::create_dir_all(path)?;
260    Ok(())
261}
262
263#[cfg(unix)]
264pub fn is_running_as_root() -> bool {
265    use nix::unistd::geteuid;
266    geteuid().is_root()
267}
268
269#[cfg(windows)]
270pub fn is_running_as_root() -> bool {
271    // Example: Attempt to read from a typically restricted system directory
272    std::fs::read_dir("C:\\Windows\\System32\\config").is_ok()
273}
274
275pub fn get_user_antnode_data_dir() -> Result<PathBuf> {
276    Ok(dirs_next::data_dir()
277        .ok_or_else(|| {
278            error!("Failed to get data_dir");
279            eyre!("Could not obtain user data directory")
280        })?
281        .join("autonomi")
282        .join("node"))
283}