1use std::path::PathBuf;
7
8pub type Result<T> = std::result::Result<T, Error>;
9
10#[derive(Debug, thiserror::Error)]
11pub enum Error {
12 #[error("io error on `{path}`: {source}")]
13 Io {
14 path: PathBuf,
15 #[source]
16 source: std::io::Error,
17 },
18
19 #[error("`{path}` is not a valid ELF object: {message}")]
20 Elf { path: PathBuf, message: String },
21
22 #[error("`{path}` is not an ELF file")]
23 NotElf { path: PathBuf },
24
25 #[error(
26 "`{path}` targets an unsupported architecture: {architecture} (e_machine = {machine:#x})"
27 )]
28 UnsupportedArchitecture {
29 path: PathBuf,
30 architecture: String,
31 machine: u16,
32 },
33
34 #[error("unable to resolve shared library `{soname}`")]
35 UnresolvedLibrary {
36 soname: String,
37 required_by: PathBuf,
38 searched: Vec<PathBuf>,
39 },
40
41 #[error("library `{soname}` is not allowed by dependency policy")]
42 DisallowedLibrary {
43 soname: String,
44 required_by: PathBuf,
45 },
46
47 #[error("resolved library `{soname}` has an incompatible architecture")]
48 IncompatibleArchitecture {
49 soname: String,
50 expected: String,
51 found: PathBuf,
52 found_architecture: String,
53 },
54
55 #[error("runtime policy feature `{feature}` could not be satisfied")]
56 MissingRuntimeFile {
57 feature: &'static str,
58 searched: Vec<PathBuf>,
59 },
60
61 #[error("{resource} exceeds the supported limit of {limit}")]
62 LimitExceeded {
63 resource: &'static str,
64 limit: usize,
65 },
66
67 #[error(
68 "source file `{path}` changed after it was added to the bundle plan (expected {expected_size} bytes with sha256 {expected_digest}, found {actual_size} bytes with sha256 {actual_digest})"
69 )]
70 SourceChanged {
71 path: PathBuf,
72 expected_digest: String,
73 expected_size: u64,
74 actual_digest: String,
75 actual_size: u64,
76 },
77
78 #[error("path `{path}` escapes the {kind} root")]
79 PathEscape { path: PathBuf, kind: &'static str },
80
81 #[error("`{path}` does not exist inside the source root")]
82 MissingSourcePath { path: PathBuf },
83
84 #[error("too many levels of symbolic links while resolving `{path}`")]
85 SymlinkLoop { path: PathBuf },
86
87 #[error("invalid configuration: {message}")]
88 Config { message: String },
89
90 #[error("invalid manifest `{path}`: {message}")]
91 Manifest { path: PathBuf, message: String },
92
93 #[error("verification failed: {failures} problem(s) across {checked} manifest entries")]
94 VerifyFailed { checked: u32, failures: u32 },
95}
96
97impl Error {
98 pub fn code(&self) -> &'static str {
103 use crate::diagnostics::error as code;
104 match self {
105 Error::Io { .. } => code::IO,
106 Error::Elf { .. } => code::ELF,
107 Error::NotElf { .. } => code::NOT_ELF,
108 Error::UnsupportedArchitecture { .. } => code::UNSUPPORTED_ARCHITECTURE,
109 Error::LimitExceeded { .. } => code::LIMIT_EXCEEDED,
110 Error::SourceChanged { .. } => code::SOURCE_CHANGED,
111 Error::UnresolvedLibrary { .. } => code::UNRESOLVED_LIBRARY,
112 Error::DisallowedLibrary { .. } => code::DISALLOWED_LIBRARY,
113 Error::IncompatibleArchitecture { .. } => code::INCOMPATIBLE_ARCHITECTURE,
114 Error::MissingRuntimeFile { .. } => code::MISSING_RUNTIME_FILE,
115 Error::PathEscape { .. } => code::PATH_ESCAPE,
116 Error::MissingSourcePath { .. } => code::MISSING_SOURCE_PATH,
117 Error::SymlinkLoop { .. } => code::SYMLINK_LOOP,
118 Error::Config { .. } => code::CONFIG,
119 Error::Manifest { .. } => code::MANIFEST,
120 Error::VerifyFailed { .. } => code::VERIFY_FAILED,
121 }
122 }
123
124 pub fn details(&self) -> Vec<String> {
126 match self {
127 Error::UnresolvedLibrary {
128 required_by,
129 searched,
130 ..
131 } => {
132 let mut out = vec![format!("required by:\n {}", required_by.display())];
133 if !searched.is_empty() {
134 let list = searched
135 .iter()
136 .map(|p| format!(" {}", p.display()))
137 .collect::<Vec<_>>()
138 .join("\n");
139 out.push(format!("searched:\n{list}"));
140 }
141 out
142 }
143 Error::DisallowedLibrary {
144 soname,
145 required_by,
146 } => vec![
147 format!("required by:\n {}", required_by.display()),
148 format!("add:\n --allow-library {soname}"),
149 ],
150 Error::IncompatibleArchitecture {
151 soname,
152 expected,
153 found,
154 found_architecture,
155 } => vec![
156 format!("requested:\n {soname} for {expected}"),
157 format!("found:\n {} ({found_architecture})", found.display()),
158 ],
159 Error::UnsupportedArchitecture { .. } => {
160 vec!["supported:\n x86_64\n aarch64".to_string()]
161 }
162 Error::MissingRuntimeFile { searched, .. } if !searched.is_empty() => {
163 let list = searched
164 .iter()
165 .map(|p| format!(" {}", p.display()))
166 .collect::<Vec<_>>()
167 .join("\n");
168 vec![format!("searched:\n{list}")]
169 }
170 _ => Vec::new(),
171 }
172 }
173}
174
175pub(crate) fn io(path: impl Into<PathBuf>, source: std::io::Error) -> Error {
176 Error::Io {
177 path: path.into(),
178 source,
179 }
180}