Skip to content
mod.rs 4.67 KiB
Newer Older
Luker's avatar
Luker committed
/*
 * Copyright (c) 2021, 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/>.
 */

Luker's avatar
Luker committed
pub mod device;
pub mod errors;
pub mod gpt;
pub mod include;
Luker's avatar
Luker committed

#[derive(::serde::Deserialize, Copy, Clone)]
#[serde(deny_unknown_fields)]
pub enum LogTime {
    UTC,
    Local,
}

#[derive(::serde::Deserialize, Copy, Clone)]
#[serde(deny_unknown_fields)]
pub enum LogFacility {
    Kern,
    User,
    Mail,
    Daemon,
    Auth,
    Syslog,
    Lpr,
    News,
    Uucp,
    Cron,
    Authpriv,
    Ftp,
    Local0,
    Local1,
    Local2,
    Local3,
    Local4,
    Local5,
    Local6,
    Local7,
}
#[derive(::serde::Deserialize, Copy, Clone)]
#[serde(deny_unknown_fields)]
pub enum LogLevel {
    Critical,
    Error,
    Warning,
    Info,
    Debug,
    Trace,
}
#[derive(::serde::Deserialize, Copy, Clone)]
#[serde(deny_unknown_fields)]
pub enum LogTermStream {
    StdErr,
    StdOut,
}
#[derive(::serde::Deserialize, Clone)]
#[serde(deny_unknown_fields)]
#[serde(rename_all = "lowercase")]
pub enum LogSyslog {
    Socket(::std::path::PathBuf),
    Udp {
        from: ::std::net::SocketAddr,
        to: ::std::net::SocketAddr,
        hostname_id: String,
    },
    Tcp {
        to: ::std::net::SocketAddr,
        hostname_id: String,
    },
}
#[derive(::serde::Deserialize, Clone)]
#[serde(rename_all = "lowercase")]
#[serde(deny_unknown_fields)]
pub enum LogDest {
    Terminal(Option<LogTermStream>),
    Syslog {
        dest: LogSyslog,
        facility: LogFacility,
        level: LogLevel,
    },
}
#[derive(::serde::Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct Logging {
    pub level: LogLevel,
    pub time: LogTime,
    #[serde(flatten)]
    pub dest: LogDest,
}
#[derive(::serde::Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct MainConfig {
    pub logging: Logging,
    pub include: ::std::path::PathBuf,
    /* Todo: only for notifications
    pub user: String,
    pub group: String,
    */
}

pub struct Config {
    pub main: MainConfig,
    pub gpts: Vec<gpt::GPT>,
    pub devices: Vec<device::Device>,
}

pub fn parse(
    logger: ::std::sync::Arc<::slog::Logger>,
    conf_path: &::std::path::Path,
) -> std::result::Result<Config, errors::ConfigError> {
    let main: MainConfig = {
        // parse file in this block so that the fopen is
        // closed as soon as possible
        let conf_device = ::std::fs::File::open(conf_path)?;
        let mut extensions = ::ron::extensions::Extensions::default();
        extensions.insert(::ron::extensions::Extensions::IMPLICIT_SOME);
        extensions.insert(::ron::extensions::Extensions::UNWRAP_NEWTYPES);
        // TODO: wait for new RON release
        //match ::ron::Options::default().
        // with_default_extensions(extensions).from_reader(&conf_device) {
        match ::ron::de::from_reader(&conf_device) {
            Ok(cfg) => cfg,
            Err(repr) => {
                ::slog::error!(logger, "on file: {:?}", &conf_path);
                ::slog::error!(logger, "{}", repr);
                return Err(errors::ConfigError::Parsing(repr));
            }
        }
    };

    let mut cfg = Config {
        main: main,
        gpts: Vec::new(),
        devices: Vec::new(),
    };

    // now parse all the included device confs

    if !cfg.main.include.is_dir() {
        ::std::eprintln!("Error: include conf directory not found");
        return Err(errors::ConfigError::IO(::std::io::Error::new(
            ::std::io::ErrorKind::NotFound,
            "include conf directory not found",
        )));
    }
    let re = ::regex::Regex::new(r"^.*\.ron$").unwrap();
    for filename in ::std::fs::read_dir(&cfg.main.include)? {
        let filename = filename?.path();
        if !re.is_match(filename.to_str().unwrap()) {
            continue;
        }
        let mut include =
            match include::parse_include(logger.clone(), &filename) {
                Ok(include) => include,
                Err(e) => {
                    return Err(e);
                }
            };
        cfg.gpts.append(&mut include.gpts);
        cfg.devices.append(&mut include.devices);
    }
    return Ok(cfg);
}