use rustix::fs::{Access, AtFlags, CWD, accessat};
use std::fs;
use super::children::Config;
pub(super) fn configuration(config: &super::config::Config) -> Result<(), String> {
let mut errors = Vec::new();
if let Err(error) = super::lys::check_secret(&config.lys.secret_file) {
errors.push(error);
}
if let Some(assistant) = &config.assistant
&& let Err(error) = super::assistant_socket::check_parent(&assistant.socket)
{
errors.push(format!("{}: {}", error.code, error.message));
}
for config in &config.children {
if let Err(error) = child(config) {
errors.push(error);
}
}
if errors.is_empty() {
Ok(())
} else {
Err(errors.join("\n"))
}
}
pub(super) fn child(config: &Config) -> Result<(), String> {
let program_error = |error| {
format!(
"door_child_program_missing: {}: {}: {error}",
config.name,
config.program.display()
)
};
let program =
fs::metadata(&config.program).map_err(|error| program_error(error.to_string()))?;
if !program.is_file() {
return Err(program_error(
"program must resolve to a regular file".to_owned(),
));
}
accessat(CWD, &config.program, Access::EXEC_OK, AtFlags::EACCESS)
.map_err(|error| program_error(error.to_string()))?;
log(config)
}
fn log(config: &Config) -> Result<(), String> {
let log_error = |error| {
format!(
"door_child_log_unwritable: {}: {}: {error}",
config.name,
config.log.display()
)
};
let mut path = config.log.clone();
loop {
match fs::metadata(&path) {
Ok(log) => {
if log.is_dir() {
return Err(log_error("log must not resolve to a folder".to_owned()));
}
return accessat(CWD, &path, Access::WRITE_OK, AtFlags::EACCESS)
.map_err(|error| log_error(error.to_string()));
}
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
Err(error) => return Err(log_error(error.to_string())),
}
match fs::symlink_metadata(&path) {
Ok(link) if link.file_type().is_symlink() => {
let target = fs::read_link(&path).map_err(|error| log_error(error.to_string()))?;
path = if target.is_absolute() {
target
} else {
path.parent()
.ok_or_else(|| log_error("log must have a parent folder".to_owned()))?
.join(target)
};
}
Ok(_) => {
return Err(log_error(
"log changed while checking its target".to_owned(),
));
}
Err(error) if error.kind() == std::io::ErrorKind::NotFound => break,
Err(error) => return Err(log_error(error.to_string())),
}
}
let folder = path
.parent()
.ok_or_else(|| log_error("log must have a parent folder".to_owned()))?;
if !fs::metadata(folder)
.map_err(|error| log_error(error.to_string()))?
.is_dir()
{
return Err(log_error("log parent must be a folder".to_owned()));
}
accessat(
CWD,
folder,
Access::WRITE_OK | Access::EXEC_OK,
AtFlags::EACCESS,
)
.map_err(|error| log_error(error.to_string()))?;
Ok(())
}