1 use std
::collections
::BTreeMap
;
2 use std
::path
::PathBuf
;
4 use anyhow
::{bail, Error}
;
8 APTRepository
, APTRepositoryFileType
, APTRepositoryOption
, APTRepositoryPackageType
,
12 pub use file
::{APTRepositoryFile, APTRepositoryFileError, APTRepositoryInfo}
;
16 const APT_SOURCES_LIST_FILENAME
: &str = "/etc/apt/sources.list";
17 const APT_SOURCES_LIST_DIRECTORY
: &str = "/etc/apt/sources.list.d/";
19 /// Calculates a common digest for successfully parsed repository files.
21 /// The digest is invariant with respect to file order.
23 /// Files without a digest are ignored.
24 fn common_digest(files
: &[APTRepositoryFile
]) -> [u8; 32] {
25 let mut digests
= BTreeMap
::new();
27 for file
in files
.iter() {
28 digests
.insert(file
.path
.clone(), &file
.digest
);
31 let mut common_raw
= Vec
::<u8>::with_capacity(digests
.len() * 32);
32 for digest
in digests
.values() {
34 Some(digest
) => common_raw
.extend_from_slice(&digest
[..]),
39 openssl
::sha
::sha256(&common_raw
[..])
42 /// Provides additional information about the repositories.
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
![];
51 for file
in files
.iter() {
52 infos
.append(&mut file
.check_suites()?
);
53 infos
.append(&mut file
.check_uris());
59 /// Returns all APT repositories configured in `/etc/apt/sources.list` and
60 /// in `/etc/apt/sources.list.d` including disabled repositories.
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.
65 /// The digest is guaranteed to be set for each successfully parsed file.
66 pub fn repositories() -> Result
<
68 Vec
<APTRepositoryFile
>,
69 Vec
<APTRepositoryFileError
>,
74 let to_result
= |files
: Vec
<APTRepositoryFile
>, errors
: Vec
<APTRepositoryFileError
>| {
75 let common_digest
= common_digest(&files
);
77 (files
, errors
, common_digest
)
80 let mut files
= vec
![];
81 let mut errors
= vec
![];
83 let sources_list_path
= PathBuf
::from(APT_SOURCES_LIST_FILENAME
);
85 let sources_list_d_path
= PathBuf
::from(APT_SOURCES_LIST_DIRECTORY
);
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
),
92 _
=> bail
!("internal error with '{}'", APT_SOURCES_LIST_FILENAME
),
95 if !sources_list_d_path
.exists() {
96 return Ok(to_result(files
, errors
));
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(),
104 return Ok(to_result(files
, errors
));
107 for entry
in std
::fs
::read_dir(sources_list_d_path
)?
{
108 let path
= entry?
.path();
110 match APTRepositoryFile
::new(path
) {
111 Ok(Some(mut file
)) => match file
.parse() {
113 if file
.digest
.is_none() {
114 bail
!("internal error - digest not set");
118 Err(err
) => errors
.push(err
),
121 Err(err
) => errors
.push(err
),
125 Ok(to_result(files
, errors
))