]>
Commit | Line | Data |
---|---|---|
b6be0f39 FE |
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; | |
76d3a5ba FE |
12 | pub use file::{APTRepositoryFile, APTRepositoryFileError, APTRepositoryInfo}; |
13 | ||
14 | mod release; | |
b6be0f39 FE |
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 | ||
76d3a5ba FE |
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 | ||
b6be0f39 FE |
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 | } |