Newer
Older
* Copyright (c) 2021-2022, Luca Fulchir <luker@fenrirproject.org>
*
* This file is part of dfim.
*
* dfim is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dfim is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dfim. If not, see <https://www.gnu.org/licenses/>.
*/
use crate::config;
use crate::config::device;
pub use crate::config::errors;
use ::std::collections::HashMap;
use ::std::ptr::NonNull;
use ::std::sync::Arc;
use ::std::sync::Mutex;
pub struct Cfg {
pub main: config::Main,
pub devices: Vec<device::Device>,
pub target_map: HashMap<String, NonNull<trgt::Target>>,
/// only safe in send/sync since the hashmap is read only
pub lock_dev: HashMap<String, Mutex<NonNull<device::Device>>>,
}
// Config can be made Send/Sync because it's read only
// do NOT modify Config after the initial check()
unsafe impl Send for Cfg {}
unsafe impl Sync for Cfg {}
impl Cfg {
pub fn new(
logger: &::slog::Logger,
mut raw_config: config::FullConfig,
) -> Result<Arc<Self>, errors::ConfigError> {
use config::CfgVerify;
raw_config.standardize();
raw_config.check_consistency(logger)?;
let mut ret = Cfg {
main: raw_config.main,
devices: raw_config.devices,
targets: raw_config.targets,
target_map: HashMap::new(),
lock_dev: HashMap::new(),
};
// build the hashmap of targets
ret.target_map = HashMap::with_capacity(ret.targets.len());
for t in &mut ret.targets {
if let Some(_) = ret.target_map.get(t.id()) {
::slog::error!(
logger,
"Same id reused multiple times: \"{}\"",
t.id()
);
return Err(errors::ConfigError::Consistency(
"reuse of the same id: \"".to_owned() + t.id() + "\"",
));
}
ret.target_map
.insert(t.id().to_string(), NonNull::new(&mut *t).unwrap());
}
// build the hashmap of devices
ret.lock_dev = HashMap::with_capacity(ret.devices.len());
for d in &mut ret.devices {
ret.lock_dev.insert(
d.id.to_string(),
Mutex::new(NonNull::new(&mut *d).unwrap()),
);
}
// check that the used did not specify non-existing ids in devices
for d in &ret.devices {
if let trgt::TargetId::Id(t) = &d.target {
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
match ret.target_map.get(t) {
Some(_) => {}
None => {
::slog::error!(
logger,
"Used a non existing id as target: \"{}\"",
t
);
return Err(errors::ConfigError::Consistency(
"Non existing id referenced as target: \""
.to_owned()
+ t
+ "\"",
));
}
}
}
}
// check that the used did not specify non-existing ids in other targets
for from in &ret.targets {
for to in &from.targets() {
match ret.target_map.get(to) {
Some(_) => {}
None => {
::slog::error!(
logger,
"Used a non existing id as target: \"{}\"",
to
);
return Err(errors::ConfigError::Consistency(
"Non existing id referenced as target: \""
.to_owned()
+ to
+ "\"",
));
}
}
}
}
// just WARN the user that some targets/devices might be unused
'unused_target: for t in &ret.targets {
for d in &ret.devices {
if let trgt::TargetId::Id(d_target_id) = &d.target {
if t.id() == d_target_id {
continue 'unused_target;
}
}
}
for t2 in &ret.targets {
if t.id() == t2.id() {
continue;
}
for dest in t2.targets() {
continue 'unused_target;
}
}
}
::slog::warn!(logger, "Unused target: \"{}\"", t.id());
}