]> git.proxmox.com Git - proxmox-apt.git/blob - src/repositories/mod.rs
add more functions to check repositories
[proxmox-apt.git] / src / repositories / mod.rs
1 use std::collections::BTreeMap;
2 use std::path::PathBuf;
3
4 use anyhow::{bail, Error};
5
6 mod repository;
7 pub use repository::{
8 APTRepository, APTRepositoryFileType, APTRepositoryOption, APTRepositoryPackageType,
9 };
10
11 mod file;
12 pub use file::{APTRepositoryFile, APTRepositoryFileError, APTRepositoryInfo};
13
14 mod release;
15
16 const APT_SOURCES_LIST_FILENAME: &str = "/etc/apt/sources.list";
17 const APT_SOURCES_LIST_DIRECTORY: &str = "/etc/apt/sources.list.d/";
18
19 /// Calculates a common digest for successfully parsed repository files.
20 ///
21 /// The digest is invariant with respect to file order.
22 ///
23 /// Files without a digest are ignored.
24 fn common_digest(files: &[APTRepositoryFile]) -> [u8; 32] {
25 let mut digests = BTreeMap::new();
26
27 for file in files.iter() {
28 digests.insert(file.path.clone(), &file.digest);
29 }
30
31 let mut common_raw = Vec::<u8>::with_capacity(digests.len() * 32);
32 for digest in digests.values() {
33 match digest {
34 Some(digest) => common_raw.extend_from_slice(&digest[..]),
35 None => (),
36 }
37 }
38
39 openssl::sha::sha256(&common_raw[..])
40 }
41
42 /// Provides additional information about the repositories.
43 ///
44 /// The kind of information can be:
45 /// `warnings` for bad suites.
46 /// `ignore-pre-upgrade-warning` when the next stable suite is configured.
47 /// `badge` for official URIs.
48 pub fn check_repositories(files: &[APTRepositoryFile]) -> Result<Vec<APTRepositoryInfo>, Error> {
49 let mut infos = vec![];
50
51 for file in files.iter() {
52 infos.append(&mut file.check_suites()?);
53 infos.append(&mut file.check_uris());
54 }
55
56 Ok(infos)
57 }
58
59 /// Returns all APT repositories configured in `/etc/apt/sources.list` and
60 /// in `/etc/apt/sources.list.d` including disabled repositories.
61 ///
62 /// Returns the succesfully parsed files, a list of errors for files that could
63 /// not be read or parsed and a common digest for the succesfully parsed files.
64 ///
65 /// The digest is guaranteed to be set for each successfully parsed file.
66 pub fn repositories() -> Result<
67 (
68 Vec<APTRepositoryFile>,
69 Vec<APTRepositoryFileError>,
70 [u8; 32],
71 ),
72 Error,
73 > {
74 let to_result = |files: Vec<APTRepositoryFile>, errors: Vec<APTRepositoryFileError>| {
75 let common_digest = common_digest(&files);
76
77 (files, errors, common_digest)
78 };
79
80 let mut files = vec![];
81 let mut errors = vec![];
82
83 let sources_list_path = PathBuf::from(APT_SOURCES_LIST_FILENAME);
84
85 let sources_list_d_path = PathBuf::from(APT_SOURCES_LIST_DIRECTORY);
86
87 match APTRepositoryFile::new(sources_list_path) {
88 Ok(Some(mut file)) => match file.parse() {
89 Ok(()) => files.push(file),
90 Err(err) => errors.push(err),
91 },
92 _ => bail!("internal error with '{}'", APT_SOURCES_LIST_FILENAME),
93 }
94
95 if !sources_list_d_path.exists() {
96 return Ok(to_result(files, errors));
97 }
98
99 if !sources_list_d_path.is_dir() {
100 errors.push(APTRepositoryFileError {
101 path: APT_SOURCES_LIST_DIRECTORY.to_string(),
102 error: "not a directory!".to_string(),
103 });
104 return Ok(to_result(files, errors));
105 }
106
107 for entry in std::fs::read_dir(sources_list_d_path)? {
108 let path = entry?.path();
109
110 match APTRepositoryFile::new(path) {
111 Ok(Some(mut file)) => match file.parse() {
112 Ok(()) => {
113 if file.digest.is_none() {
114 bail!("internal error - digest not set");
115 }
116 files.push(file);
117 }
118 Err(err) => errors.push(err),
119 },
120 Ok(None) => (),
121 Err(err) => errors.push(err),
122 }
123 }
124
125 Ok(to_result(files, errors))
126 }