Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
a7f2a4ead0 | |||
bb88e5f0b8 | |||
e5b9f185c5 | |||
fcd1a4dc7d | |||
6c2b47d4f4 | |||
adf2180d11 | |||
b3f2204a88 | |||
4510e3500d | |||
3b9396c500 | |||
853be957ee | |||
f82ff6ac72 |
|
@ -3,11 +3,17 @@ name = "cuvat-rs"
|
|||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "cuvat"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.0", features = ["derive"] }
|
||||
serde = { version = "1", features = ["serde_derive"] }
|
||||
serde_json = { version = "1.0" }
|
||||
toml = { version = "0.8" }
|
||||
updateinfo-xmlparser = { git = "https://git.zhgsun.com:8089/jiachao2130/updateinfo-xmlparser.git", version = "0.1.0" }
|
||||
updateinfo-xmlparser = { git = "https://git.zhgsun.com:8089/jiachao2130/updateinfo-xmlparser.git", version = "0.1.1" }
|
||||
cvrf-xmlparser = { git = "https://git.zhgsun.com:8089/jiachao2130/cvrf-xmlparser.git", version = "0.1.0" }
|
||||
rpm-rs = { git = "https://git.zhgsun.com:8089/jiachao2130/rpm-rs.git", version = "0.1.0" }
|
||||
lazy_static = { version = "1.5" }
|
||||
ccutils = { git = "https://git.zhgsun.com:8089/jiachao2130/ccutils.git", version = "0.1.0" }
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use cvrf_xmlparser::{SaInfo, CVE};
|
||||
use cvrf_xmlparser::{CUSA, CVE};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use updateinfo_xmlparser::{UpdateInfoDb, RpmInfo};
|
||||
use updateinfo_xmlparser::{RpmInfo, UpdateInfoDb};
|
||||
|
||||
// PackageDb 从 updateinfo 中获取
|
||||
// 以包名为键,值为一个 Vector ,里面包含更新的不同版本的 rpm 包信息
|
||||
|
@ -13,9 +13,7 @@ pub struct PackgeDb {
|
|||
|
||||
impl PackgeDb {
|
||||
pub fn new() -> Self {
|
||||
PackgeDb {
|
||||
db: HashMap::new(),
|
||||
}
|
||||
PackgeDb { db: HashMap::new() }
|
||||
}
|
||||
|
||||
/// 从已有的 updateinfo 仓库文件中,获取所有与安全更新相关的软件包
|
||||
|
@ -43,24 +41,26 @@ impl PackgeDb {
|
|||
// 其键为 SA id,值为详情
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SaDb {
|
||||
db: HashMap<String, SaInfo>,
|
||||
db: HashMap<String, CUSA>,
|
||||
}
|
||||
|
||||
impl SaDb {
|
||||
pub fn new() -> Self {
|
||||
SaDb {
|
||||
db: HashMap::new(),
|
||||
}
|
||||
SaDb { db: HashMap::new() }
|
||||
}
|
||||
|
||||
/// 一般来自对 cvrf 文件解析并转换为 SaInfo 的文本数据文件
|
||||
pub fn db(&self) -> &HashMap<String, CUSA> {
|
||||
&self.db
|
||||
}
|
||||
|
||||
/// 一般来自对 cvrf 文件解析并转换为 CUSA 的文本数据文件
|
||||
pub fn load_from_file(&mut self, file: &str) -> crate::Result<()> {
|
||||
let data = std::fs::read_to_string(file)?;
|
||||
self.db = toml::from_str(&data)?;
|
||||
self.db = serde_json::from_str(&data)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 从 SaInfo 中提取出所有的 CVE 源
|
||||
/// 从 CUSA 中提取出所有的 CVE 源
|
||||
pub fn get_cvedb(&self) -> CveDb {
|
||||
let mut cvedb = CveDb::new();
|
||||
|
||||
|
@ -84,9 +84,7 @@ pub struct CveDb {
|
|||
impl CveDb {
|
||||
#[allow(dead_code)]
|
||||
pub fn new() -> Self {
|
||||
CveDb {
|
||||
db: HashMap::new(),
|
||||
}
|
||||
CveDb { db: HashMap::new() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,43 +1,104 @@
|
|||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::process::Command;
|
||||
use std::str::FromStr;
|
||||
|
||||
use ccutils::cmd::IsOk;
|
||||
use cvrf_xmlparser::{Severity, CUSA};
|
||||
use lazy_static::lazy_static;
|
||||
use rpm_rs::rpm::{
|
||||
get_installed_packages,
|
||||
Package,
|
||||
};
|
||||
use rpm_rs::rpm::{get_installed_packages, Package};
|
||||
use rpm_rs::rpmio::rpmvercmp;
|
||||
use updateinfo_xmlparser::{UpdateInfoDb, RpmInfo};
|
||||
use updateinfo_xmlparser::{RpmInfo, UpdateInfoDb};
|
||||
|
||||
use crate::analyzer::db::{CveDb, PackgeDb, SaDb};
|
||||
use crate::cli::Cli;
|
||||
use crate::analyzer::db::PackgeDb;
|
||||
use crate::CONFIG;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref update_pkgs: PackgeDb= {
|
||||
pub static ref update_pkgs: PackgeDb = {
|
||||
let mut updatedb = UpdateInfoDb::new();
|
||||
updatedb.load_xml("test/updateinfo.xml").unwrap();
|
||||
updatedb.load_xml(&CONFIG.updateinfo()).unwrap();
|
||||
|
||||
let mut pkgdb = PackgeDb::new();
|
||||
pkgdb.load_from_updateinfodb(&updatedb);
|
||||
pkgdb
|
||||
};
|
||||
pub static ref sadb: SaDb = {
|
||||
let mut _sadb = SaDb::new();
|
||||
|
||||
_sadb.load_from_file(&CONFIG.sainfo()).unwrap();
|
||||
_sadb
|
||||
};
|
||||
pub static ref cvedb: CveDb = sadb.get_cvedb();
|
||||
}
|
||||
|
||||
pub mod db;
|
||||
|
||||
struct Reporter {
|
||||
// 已修复的安全更新
|
||||
fixed: HashMap<CUSA, HashSet<RpmInfo>>,
|
||||
|
||||
// 可用的安全更新
|
||||
avaliable: HashMap<CUSA, HashSet<RpmInfo>>,
|
||||
}
|
||||
|
||||
impl Reporter {
|
||||
// 新建一个空的 Reporter
|
||||
pub fn new() -> Self {
|
||||
let fixed = HashMap::new();
|
||||
let avaliable = HashMap::new();
|
||||
|
||||
Self { fixed, avaliable }
|
||||
}
|
||||
|
||||
// get fixed, 不可写
|
||||
pub fn get_fixed(&self) -> &HashMap<CUSA, HashSet<RpmInfo>> {
|
||||
&self.fixed
|
||||
}
|
||||
|
||||
// get avaliable, 只读
|
||||
pub fn get_avaliable(&self) -> &HashMap<CUSA, HashSet<RpmInfo>> {
|
||||
&self.avaliable
|
||||
}
|
||||
|
||||
// 添加包到已修复
|
||||
pub fn add_to_fixed(&mut self, cusa: &CUSA, rpm: RpmInfo) {
|
||||
// 可以找到则直接 insert
|
||||
if let Some(rpms) = self.fixed.get_mut(cusa) {
|
||||
rpms.insert(rpm);
|
||||
} else {
|
||||
let mut rpms = HashSet::new();
|
||||
rpms.insert(rpm);
|
||||
self.fixed.insert(cusa.clone(), rpms);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加包到可用更新
|
||||
pub fn add_to_avaliable(&mut self, cusa: &CUSA, rpm: RpmInfo) {
|
||||
// 可以找到则直接 insert
|
||||
if let Some(rpms) = self.avaliable.get_mut(cusa) {
|
||||
rpms.insert(rpm);
|
||||
} else {
|
||||
let mut rpms = HashSet::new();
|
||||
rpms.insert(rpm);
|
||||
self.avaliable.insert(cusa.clone(), rpms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cuvat_run(cli: &Cli) -> crate::Result<()> {
|
||||
// 只报告 cve 相关
|
||||
if cli.cves {
|
||||
return list_cves(cli)
|
||||
return list_cves(cli);
|
||||
}
|
||||
|
||||
// 只报告 sa 相关
|
||||
if cli.sas {
|
||||
return list_sas(cli)
|
||||
return list_sas(cli);
|
||||
}
|
||||
|
||||
// 生成报告
|
||||
if cli.report {
|
||||
return repoter(cli)
|
||||
return repoter(cli);
|
||||
}
|
||||
|
||||
// 默认报告格式
|
||||
|
@ -45,71 +106,338 @@ pub fn cuvat_run(cli: &Cli) -> crate::Result<()> {
|
|||
}
|
||||
|
||||
fn list_cves(cli: &Cli) -> crate::Result<()> {
|
||||
if cli.dnf {
|
||||
return _dnf_list_cves(cli);
|
||||
}
|
||||
|
||||
let reporter = _reporter()?;
|
||||
let avaliable = reporter.get_avaliable();
|
||||
let severity = Severity::from_str(&cli.severity)?;
|
||||
let mut _cves = HashSet::new();
|
||||
cli.sources.iter().for_each(|id| {
|
||||
_cves.insert(id);
|
||||
});
|
||||
|
||||
let mut cves = HashSet::new();
|
||||
let mut msg = String::new();
|
||||
|
||||
// 仅针对可用更新
|
||||
for (cusa, _) in avaliable {
|
||||
// 过滤
|
||||
if cusa.severity() < &severity {
|
||||
continue;
|
||||
}
|
||||
|
||||
cusa.cves().iter().for_each(|cve| {
|
||||
if let Some(_) = _cves.get(&cve.id) {
|
||||
let _ = cves.insert(cve.clone());
|
||||
_cves.remove(&cve.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for cve in &cves {
|
||||
if cli.info {
|
||||
msg = format!("{msg}\n\n{cve:#?}");
|
||||
} else {
|
||||
msg = format!("{msg}\n{}", cve.id);
|
||||
}
|
||||
}
|
||||
|
||||
if !_cves.is_empty() {
|
||||
msg = format!("{msg}\n\nUnaffected CVEs:\n{_cves:#?}")
|
||||
}
|
||||
|
||||
println!("{msg}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn _dnf_list_cves(_cli: &Cli) -> crate::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn list_sas(cli: &Cli) -> crate::Result<()> {
|
||||
if cli.dnf {
|
||||
return _dnf_list_sas(cli);
|
||||
}
|
||||
|
||||
let reporter = _reporter()?;
|
||||
let avaliable = reporter.get_avaliable();
|
||||
let severity = Severity::from_str(&cli.severity)?;
|
||||
let mut _sas = HashSet::new();
|
||||
cli.sources.iter().for_each(|id| {
|
||||
_sas.insert(id);
|
||||
});
|
||||
|
||||
let mut sas = HashSet::new();
|
||||
let mut msg = String::new();
|
||||
|
||||
// 仅针对可用更新
|
||||
for (cusa, _) in avaliable {
|
||||
// 过滤
|
||||
if cusa.severity() < &severity {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(_) = _sas.get(&cusa.id) {
|
||||
let _ = sas.insert(cusa.clone());
|
||||
_sas.remove(&cusa.id);
|
||||
}
|
||||
}
|
||||
|
||||
for sa in &sas {
|
||||
if cli.info {
|
||||
msg = format!("{msg}\n\n{sa:#?}");
|
||||
} else {
|
||||
msg = format!("{msg}\n{}", sa.id);
|
||||
}
|
||||
}
|
||||
|
||||
if !_sas.is_empty() {
|
||||
msg = format!("{msg}\n\nUnaffected SAs:\n{_sas:#?}")
|
||||
}
|
||||
|
||||
println!("{msg}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn repoter(cli: &Cli) -> crate::Result<()> {
|
||||
fn _dnf_list_sas(_cli: &Cli) -> crate::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// 最为详尽的报告,包括当前系统中软件包所涉及到,已修复和可用但未修复
|
||||
// 的所有软件包的列表。
|
||||
// 其格式如下:
|
||||
// XXXXXX 报告
|
||||
// FIXED:
|
||||
// SA ID
|
||||
// CVES
|
||||
// effected rpms list
|
||||
// ...
|
||||
//
|
||||
// ====================
|
||||
// AVALIABLE:
|
||||
// SA ID
|
||||
// CVES
|
||||
// effected rpms list
|
||||
// ...
|
||||
//
|
||||
fn repoter(cli: &Cli) -> crate::Result<()> {
|
||||
if cli.dnf {
|
||||
println!("暂不支持此功能,请联系开发者");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let reporter = _reporter()?;
|
||||
let fixed = reporter.get_fixed();
|
||||
let avaliable = reporter.get_avaliable();
|
||||
let mut msg = String::new();
|
||||
|
||||
msg = format!("{msg}系统漏洞信息检测报告\n\n");
|
||||
|
||||
// fixed
|
||||
msg = format!("{msg}已修复的安全公告\n");
|
||||
for (cusa, rpms) in fixed {
|
||||
// sa cves 信息
|
||||
msg = format!("{msg}{} (fixed):\n", cusa.id());
|
||||
let mut cves = vec![];
|
||||
cusa.cves().iter().for_each(|cve| {
|
||||
cves.push(&cve.id);
|
||||
});
|
||||
msg = format!("{msg}{:2}涉及 CVE 列表:{:?}\n", "", cves);
|
||||
|
||||
for rpm in rpms {
|
||||
msg = format!("{msg}{:4}{}\n", "", rpm.nevra());
|
||||
}
|
||||
// 空
|
||||
msg = format!("{msg}\n");
|
||||
}
|
||||
|
||||
// "==============="
|
||||
let mut seprator = String::new();
|
||||
for _ in 0..80 {
|
||||
seprator.push('=');
|
||||
}
|
||||
msg = format!("{msg}\n{seprator}\n\n\n");
|
||||
|
||||
// avaliable updates
|
||||
msg = format!("{msg}可用更新\n");
|
||||
for (cusa, rpms) in avaliable {
|
||||
// sa cves 信息
|
||||
msg = format!("{msg}{} (avaliable):\n", cusa.id());
|
||||
let mut cves = vec![];
|
||||
cusa.cves().iter().for_each(|cve| {
|
||||
cves.push(&cve.id);
|
||||
});
|
||||
msg = format!("{msg}{:2}涉及 CVE 列表:{:?}\n", "", cves);
|
||||
|
||||
for rpm in rpms {
|
||||
msg = format!("{msg}{:4}{}\n", "", rpm.nevra());
|
||||
}
|
||||
// 空
|
||||
msg = format!("{msg}\n");
|
||||
}
|
||||
|
||||
println!("{msg}");
|
||||
|
||||
// summary 一下
|
||||
summary(cli)
|
||||
}
|
||||
|
||||
fn summary(cli: &Cli) -> crate::Result<()> {
|
||||
let mut sa_ids: HashSet<String> = HashSet::new();
|
||||
if cli.dnf {
|
||||
return _dnf_summary(cli);
|
||||
}
|
||||
|
||||
let reporter = _reporter()?;
|
||||
let avaliable = reporter.get_avaliable();
|
||||
let severity = Severity::from_str(&cli.severity)?;
|
||||
let mut total = 0;
|
||||
let mut res = vec![0; 5];
|
||||
let mut lists = vec![vec![]; 5];
|
||||
let mut msg = String::new();
|
||||
|
||||
for (cusa, _) in avaliable {
|
||||
// 过滤
|
||||
if cusa.severity() < &severity {
|
||||
continue;
|
||||
}
|
||||
|
||||
let pos: usize = cusa.severity().into();
|
||||
total += 1;
|
||||
res[pos] += 1;
|
||||
lists[pos].push(cusa);
|
||||
}
|
||||
|
||||
// 如果需要列出详细的 sa
|
||||
if cli.list {
|
||||
msg = format!("当前系统未修复的公告列表(共 {total} 个):\n");
|
||||
for sas in &lists {
|
||||
for sa in sas {
|
||||
msg = format!("{msg}\n{:>4}{}: {:?}", "", sa.id(), sa.severity());
|
||||
}
|
||||
}
|
||||
//msg = format!("{msg}\n\n");
|
||||
} else {
|
||||
msg = format!(
|
||||
"{msg}
|
||||
本次安全检查共扫描出 {} 个漏洞:
|
||||
|
||||
致命漏洞:{:>3} 个
|
||||
高危漏洞:{:>3} 个
|
||||
中危漏洞:{:>3} 个
|
||||
低危漏洞:{:>3} 个
|
||||
",
|
||||
total, res[4], res[3], res[2], res[1]
|
||||
);
|
||||
}
|
||||
|
||||
println!("{msg}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn _dnf_summary(_cli: &Cli) -> crate::Result<()> {
|
||||
let cmd = Command::new("dnf")
|
||||
.arg("updateinfo")
|
||||
.output()
|
||||
.expect("执行 `dnf udpateinfo` 命令失败");
|
||||
|
||||
match cmd.result() {
|
||||
Ok(res) => println!("{res}"),
|
||||
Err(err) => eprintln!("{err}"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn _reporter() -> crate::Result<Reporter> {
|
||||
let mut reporter = Reporter::new();
|
||||
// 当前系统所有已安装的 rpm 包
|
||||
let installed = get_installed_packages();
|
||||
// installed 已被消费掉
|
||||
// latest_installed 是所有最新版本软件包的 Vec
|
||||
let latest_installed: Vec<Package> = installed.into_iter().map(|(_, pkgs)| {
|
||||
let mut latest = pkgs[0].clone();
|
||||
for pkg in pkgs.into_iter() {
|
||||
latest = rpmdb_package_vercmp(latest, pkg);
|
||||
}
|
||||
latest
|
||||
}).collect();
|
||||
let latest_installed: Vec<Package> = installed
|
||||
.into_iter()
|
||||
.map(|(_, pkgs)| {
|
||||
let mut latest = pkgs[0].clone();
|
||||
for pkg in pkgs.into_iter() {
|
||||
latest = rpmdb_package_vercmp(latest, pkg);
|
||||
}
|
||||
latest
|
||||
})
|
||||
.collect();
|
||||
|
||||
// 获取 sa 更新列表
|
||||
for pkg in latest_installed {
|
||||
let name = pkg.name();
|
||||
if let Some(updates) = update_pkgs.db().get(name) {
|
||||
for update in updates {
|
||||
// 因 updateinfo 里包含所有架构,故于此做个判断
|
||||
// 是否考虑架构信息在不同的版本有所不同?
|
||||
if update.arch() != pkg.arch().unwrap() {
|
||||
continue;
|
||||
}
|
||||
let sainfo = sadb.db().get(update.sa()).unwrap();
|
||||
// epoch 判断
|
||||
match (update.epoch(), pkg.epoch()) {
|
||||
(Some(_), None) => {
|
||||
let _ = sa_ids.insert(update.sa().into());
|
||||
},
|
||||
(None, Some(_)) => continue,
|
||||
reporter.add_to_avaliable(&sainfo, update.clone());
|
||||
}
|
||||
(None, Some(_)) => {
|
||||
reporter.add_to_fixed(&sainfo, update.clone());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// evr 对比
|
||||
if rpmvercmp(&update.evr(), &pkg.evr()) > 0 {
|
||||
sa_ids.insert(update.sa().into());
|
||||
reporter.add_to_avaliable(&sainfo, update.clone());
|
||||
} else {
|
||||
reporter.add_to_fixed(&sainfo, update.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("{:#?}", sa_ids.len());
|
||||
// TODO: sa -> { rpms, cves }
|
||||
|
||||
Ok(())
|
||||
Ok(reporter)
|
||||
}
|
||||
|
||||
// 对比两个 rpm Package 的版本,返回最新的一个
|
||||
// TODO: 使用 RpmInfo 作为对比对象
|
||||
fn rpmdb_package_vercmp(pa: Package, pb: Package) -> Package {
|
||||
// 首先进行 epoch 的比较
|
||||
match (pa.epoch(), pb.epoch()) {
|
||||
(Some(_), None) => return pa,
|
||||
(None, Some(_)) => return pb,
|
||||
_ => {}, // 继续往下对比
|
||||
_ => {} // 继续往下对比
|
||||
}
|
||||
|
||||
if rpmvercmp(&pa.evr(), &pb.evr()) > 0 {
|
||||
return pa
|
||||
return pa;
|
||||
} else {
|
||||
return pb
|
||||
return pb;
|
||||
}
|
||||
}
|
||||
|
||||
// 将 RPMDB 里的 Package 转换为 RpmInfo,方便统一进行版本对比和处理。
|
||||
fn package2rpminfo(pkg: Package) -> RpmInfo {
|
||||
let mut rpminfo = RpmInfo::new();
|
||||
|
||||
// 目前只需要将 name/epoch/version/release/arch 几项填充即可
|
||||
rpminfo.set("name", pkg.name().to_string());
|
||||
// Option<i32> => String
|
||||
if let Some(epoch) = pkg.epoch() {
|
||||
rpminfo.set("epoch", epoch.to_string());
|
||||
}
|
||||
rpminfo.set("version", pkg.version().to_string());
|
||||
rpminfo.set("release", pkg.release().to_string());
|
||||
// Option<&str> => String
|
||||
if let Some(arch) = pkg.arch() {
|
||||
rpminfo.set("arch", arch.to_string());
|
||||
}
|
||||
|
||||
rpminfo
|
||||
}
|
||||
|
|
|
@ -14,11 +14,11 @@ pub struct Cli {
|
|||
#[arg(short, long, default_value_t = false)]
|
||||
pub list: bool,
|
||||
|
||||
/// 列出并查看已修复但尚未更新的 cve 漏洞信息
|
||||
/// 查找并列出并查看已修复但尚未更新的 cve 漏洞信息
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub cves: bool,
|
||||
|
||||
/// 列出并查看已修复但尚未更新的 sa 安全公告信息
|
||||
/// 查找并列出并查看已修复但尚未更新的 sa 安全公告信息
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub sas: bool,
|
||||
|
||||
|
@ -30,8 +30,8 @@ pub struct Cli {
|
|||
#[arg(action = clap::ArgAction::Append)]
|
||||
pub sources: Vec<String>,
|
||||
|
||||
/// 设置过滤级别,由高到低为:[Critical, Important, Moderate, Low]
|
||||
#[arg(long, default_value_t = String::from("Low"))]
|
||||
/// 设置过滤级别,由高到低为:[Critical, High, Medium, Low, None]
|
||||
#[arg(long, default_value_t = String::from("None"))]
|
||||
pub severity: String,
|
||||
|
||||
/// 生成漏洞扫描报告
|
||||
|
|
44
src/config.rs
Normal file
44
src/config.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// 可编辑的配置,一般位于 /etc/cuavrs 下
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Config {
|
||||
// 从此处更新 updateinfo, 以及 cusa 数据库
|
||||
remote: String,
|
||||
|
||||
// 本地数据存储位置
|
||||
// /var/cache/cuvars
|
||||
local: String,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
// 从文件中读取配置信息
|
||||
pub fn from(path: &str) -> crate::Result<Self> {
|
||||
let data = std::fs::read_to_string(path)?;
|
||||
|
||||
Ok(serde_json::from_str::<Self>(&data)?)
|
||||
}
|
||||
|
||||
// 从此地址获取更新
|
||||
pub fn remote(&self) -> &str {
|
||||
&self.remote
|
||||
}
|
||||
|
||||
// 本地数据存储位置
|
||||
pub fn local(&self) -> &str {
|
||||
&self.local
|
||||
}
|
||||
|
||||
pub fn update(&self) -> crate::Result<()> {
|
||||
// TODO
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn updateinfo(&self) -> String {
|
||||
format!("{}/updateinfo.xml", &self.local)
|
||||
}
|
||||
|
||||
pub fn sainfo(&self) -> String {
|
||||
format!("{}/sainfos.json", &self.local)
|
||||
}
|
||||
}
|
19
src/lib.rs
19
src/lib.rs
|
@ -1,4 +1,10 @@
|
|||
use std::path::Path;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
pub mod cli;
|
||||
pub mod config;
|
||||
use config::Config;
|
||||
|
||||
mod analyzer;
|
||||
|
||||
|
@ -9,6 +15,19 @@ pub type Error = Box<dyn std::error::Error + Send + Sync>;
|
|||
/// 定义 crate::Result
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
// 首先需要读取并载入配置信息
|
||||
// 默认为 /etc/cuavrs 下
|
||||
lazy_static! {
|
||||
pub static ref CONFIG: Config = {
|
||||
let default = Path::new("/etc/cuavrs/cuvat.json");
|
||||
if default.is_file() {
|
||||
Config::from(default.to_str().unwrap()).unwrap()
|
||||
} else {
|
||||
Config::from("cuvat.json").unwrap()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn cumain() -> Result<()> {
|
||||
let cli = cli::parse();
|
||||
// 初始化使用 rpm 默认配置
|
||||
|
|
43386
test/cvrf_sainfos.json
Normal file
43386
test/cvrf_sainfos.json
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user