Skip to content

Commit 2fd3ab2

Browse files
committed
Change error-chain to thiserror
1 parent 106e112 commit 2fd3ab2

File tree

12 files changed

+147
-92
lines changed

12 files changed

+147
-92
lines changed

Cargo.toml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@ edition = "2018"
1313
[badges]
1414
travis-ci = { repository = "mullvad/pfctl-rs" }
1515

16-
1716
[dependencies]
18-
errno = "0.2"
19-
error-chain = "0.12"
20-
ioctl-sys = "0.6.0"
17+
derive_builder = "0.20"
18+
errno = "0.3"
19+
ioctl-sys = "0.8"
20+
ipnetwork = "0.20"
2121
libc = "0.2.29"
22-
derive_builder = "0.9"
23-
ipnetwork = "0.16"
22+
thiserror = "1"
2423

2524
[dev-dependencies]
2625
assert_matches = "1.1.0"
27-
uuid = { version = "0.8", features = ["v4"] }
26+
error-chain = "0.12"
2827
scopeguard = "1.0"
28+
uuid = { version = "1", features = ["v4"] }

examples/enable.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ fn run() -> Result<()> {
2121
// Try to enable the firewall. Equivalent to the CLI command "pfctl -e".
2222
match pf.enable() {
2323
Ok(_) => println!("Enabled PF"),
24-
Err(pfctl::Error(pfctl::ErrorKind::StateAlreadyActive, _)) => (),
24+
Err(pfctl::Error {
25+
source: pfctl::ErrorSource::StateAlreadyActive(_),
26+
..
27+
}) => (),
2528
err => err.chain_err(|| "Unable to enable PF")?,
2629
}
2730
Ok(())

src/lib.rs

Lines changed: 94 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,14 @@
5959
6060
#![deny(rust_2018_idioms)]
6161

62-
#[macro_use]
63-
pub extern crate error_chain;
64-
6562
use std::{
6663
ffi::CStr,
64+
fmt::Display,
6765
fs::File,
6866
mem,
6967
os::unix::io::{AsRawFd, RawFd},
7068
};
69+
use thiserror::Error;
7170

7271
pub use ipnetwork;
7372

@@ -92,40 +91,87 @@ pub use crate::ruleset::*;
9291
mod transaction;
9392
pub use crate::transaction::*;
9493

95-
mod errors {
96-
error_chain! {
97-
errors {
98-
DeviceOpenError(s: &'static str) {
99-
description("Unable to open PF device file")
100-
display("Unable to open PF device file at '{}'", s)
101-
}
102-
InvalidArgument(s: &'static str) {
103-
display("Invalid argument: {}", s)
104-
}
105-
StateAlreadyActive {
106-
description("Target state is already active")
107-
}
108-
InvalidRuleCombination(s: String) {
109-
description("Rule contains incompatible values")
110-
display("Incompatible values in rule: {}", s)
111-
}
112-
AnchorDoesNotExist {
113-
display("Anchor does not exist")
114-
}
94+
#[derive(Error, Debug)]
95+
pub enum ErrorSource {
96+
#[error("Unable to open PF device file at {}", _0)]
97+
DeviceOpen(&'static str, #[source] ::std::io::Error),
98+
99+
#[error("Lower port is greater than upper port.")]
100+
LowerIsGreaterPort,
101+
102+
#[error("String does not fit destination")]
103+
StrCopyNotFits,
104+
105+
#[error("String has null byte")]
106+
StrCopyNullByte,
107+
108+
#[error("Target state is already active")]
109+
StateAlreadyActive(#[source] ::std::io::Error),
110+
111+
#[error("Incompatible values in rule: {}", _0)]
112+
InvalidRuleCombination(String),
113+
114+
#[error("Anchor does not exist")]
115+
AnchorDoesNotExist,
116+
117+
#[error("Cstr not null terminated")]
118+
CstrNotTerminated,
119+
120+
#[error("Ioctl Error")]
121+
Ioctl(#[from] ::std::io::Error),
122+
}
123+
124+
#[derive(Error, Debug)]
125+
pub struct Error {
126+
pub info: Option<ErrorInfo>,
127+
#[source]
128+
pub source: ErrorSource,
129+
}
130+
131+
impl Error {
132+
fn new(info: ErrorInfo, err: Error) -> Self {
133+
Self {
134+
info: Some(info),
135+
source: err.source,
115136
}
116-
foreign_links {
117-
IoctlError(::std::io::Error);
137+
}
138+
}
139+
140+
impl Display for Error {
141+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142+
if let Some(info) = self.info.as_ref() {
143+
info.fmt(f)?;
118144
}
145+
self.source.fmt(f)
119146
}
120147
}
121-
pub use crate::errors::*;
122148

123-
/// Returns the given input result, except if it is an `Err` matching the given `ErrorKind`,
149+
impl From<ErrorSource> for Error {
150+
fn from(source: ErrorSource) -> Self {
151+
Self { info: None, source }
152+
}
153+
}
154+
155+
#[derive(Error, Debug)]
156+
pub enum ErrorInfo {
157+
#[error("Invalid anchor name")]
158+
InvalidAnchorName,
159+
160+
#[error("Incompatible interface name")]
161+
IncompatibleInterfaceName,
162+
163+
#[error("Invalid route target")]
164+
InvalidRouteTarget,
165+
}
166+
167+
pub type Result<T> = ::std::result::Result<T, Error>;
168+
169+
/// Returns the given input result, except if it is an `Err` matching the given `Error`,
124170
/// then it returns `Ok(())` instead, so the error is ignored.
125171
macro_rules! ignore_error_kind {
126172
($result:expr, $kind:pat) => {
127173
match $result {
128-
Err($crate::Error($kind, _)) => Ok(()),
174+
Err($crate::Error { source: $kind, .. }) => Ok(()),
129175
result => result,
130176
}
131177
};
@@ -148,7 +194,9 @@ use crate::conversion::*;
148194

149195
/// Internal function to safely compare Rust string with raw C string slice
150196
fn compare_cstr_safe(s: &str, cchars: &[std::os::raw::c_char]) -> Result<bool> {
151-
ensure!(cchars.iter().any(|&c| c == 0), "Not null terminated");
197+
if !(cchars.iter().any(|&c| c == 0)) {
198+
return Err(ErrorSource::CstrNotTerminated.into());
199+
}
152200
let cs = unsafe { CStr::from_ptr(cchars.as_ptr()) };
153201
Ok(s.as_bytes() == cs.to_bytes())
154202
}
@@ -174,7 +222,7 @@ impl PfCtl {
174222
/// Same as `enable`, but `StateAlreadyActive` errors are supressed and exchanged for
175223
/// `Ok(())`.
176224
pub fn try_enable(&mut self) -> Result<()> {
177-
ignore_error_kind!(self.enable(), ErrorKind::StateAlreadyActive)
225+
ignore_error_kind!(self.enable(), crate::ErrorSource::StateAlreadyActive(_))
178226
}
179227

180228
/// Tries to disable PF. If the firewall is already disabled it will return an
@@ -186,7 +234,7 @@ impl PfCtl {
186234
/// Same as `disable`, but `StateAlreadyActive` errors are supressed and exchanged for
187235
/// `Ok(())`.
188236
pub fn try_disable(&mut self) -> Result<()> {
189-
ignore_error_kind!(self.disable(), ErrorKind::StateAlreadyActive)
237+
ignore_error_kind!(self.disable(), crate::ErrorSource::StateAlreadyActive(_))
190238
}
191239

192240
/// Tries to determine if PF is enabled or not.
@@ -201,7 +249,7 @@ impl PfCtl {
201249

202250
pfioc_rule.rule.action = kind.into();
203251
name.try_copy_to(&mut pfioc_rule.anchor_call[..])
204-
.chain_err(|| ErrorKind::InvalidArgument("Invalid anchor name"))?;
252+
.map_err(|e| Error::new(ErrorInfo::InvalidAnchorName, e))?;
205253

206254
ioctl_guard!(ffi::pf_insert_rule(self.fd(), &mut pfioc_rule))?;
207255
Ok(())
@@ -210,7 +258,10 @@ impl PfCtl {
210258
/// Same as `add_anchor`, but `StateAlreadyActive` errors are supressed and exchanged for
211259
/// `Ok(())`.
212260
pub fn try_add_anchor(&mut self, name: &str, kind: AnchorKind) -> Result<()> {
213-
ignore_error_kind!(self.add_anchor(name, kind), ErrorKind::StateAlreadyActive)
261+
ignore_error_kind!(
262+
self.add_anchor(name, kind),
263+
crate::ErrorSource::StateAlreadyActive(_)
264+
)
214265
}
215266

216267
pub fn remove_anchor(&mut self, name: &str, kind: AnchorKind) -> Result<()> {
@@ -224,7 +275,7 @@ impl PfCtl {
224275
pub fn try_remove_anchor(&mut self, name: &str, kind: AnchorKind) -> Result<()> {
225276
ignore_error_kind!(
226277
self.remove_anchor(name, kind),
227-
ErrorKind::AnchorDoesNotExist
278+
crate::ErrorSource::AnchorDoesNotExist
228279
)
229280
}
230281

@@ -236,7 +287,7 @@ impl PfCtl {
236287
pfioc_rule.ticket = utils::get_ticket(self.fd(), &anchor, AnchorKind::Filter)?;
237288
anchor
238289
.try_copy_to(&mut pfioc_rule.anchor[..])
239-
.chain_err(|| ErrorKind::InvalidArgument("Invalid anchor name"))?;
290+
.map_err(|e| Error::new(ErrorInfo::InvalidAnchorName, e))?;
240291
rule.try_copy_to(&mut pfioc_rule.rule)?;
241292

242293
pfioc_rule.action = ffi::pfvar::PF_CHANGE_ADD_TAIL as u32;
@@ -287,7 +338,7 @@ impl PfCtl {
287338

288339
/// Clear states created by rules in anchor.
289340
/// Returns total number of removed states upon success, otherwise
290-
/// ErrorKind::AnchorDoesNotExist if anchor does not exist.
341+
/// Error::AnchorDoesNotExist if anchor does not exist.
291342
pub fn clear_states(&mut self, anchor_name: &str, kind: AnchorKind) -> Result<u32> {
292343
let pfsync_states = self.get_states()?;
293344
if !pfsync_states.is_empty() {
@@ -317,7 +368,7 @@ impl PfCtl {
317368
let mut pfioc_state_kill = unsafe { mem::zeroed::<ffi::pfvar::pfioc_state_kill>() };
318369
interface
319370
.try_copy_to(&mut pfioc_state_kill.psk_ifname)
320-
.chain_err(|| ErrorKind::InvalidArgument("Incompatible interface name"))?;
371+
.map_err(|e| Error::new(ErrorInfo::IncompatibleInterfaceName, e))?;
321372
ioctl_guard!(ffi::pf_clear_states(self.fd(), &mut pfioc_state_kill))?;
322373
// psk_af holds the number of killed states
323374
Ok(pfioc_state_kill.psk_af as u32)
@@ -342,7 +393,7 @@ impl PfCtl {
342393
/// The return value from closure is transparently passed to the caller.
343394
///
344395
/// - Returns Result<R> from call to closure on match.
345-
/// - Returns `ErrorKind::AnchorDoesNotExist` on mismatch, the closure is not called in that
396+
/// - Returns `Error::AnchorDoesNotExist` on mismatch, the closure is not called in that
346397
/// case.
347398
fn with_anchor_rule<F, R>(&self, name: &str, kind: AnchorKind, f: F) -> Result<R>
348399
where
@@ -359,7 +410,7 @@ impl PfCtl {
359410
return f(pfioc_rule);
360411
}
361412
}
362-
bail!(ErrorKind::AnchorDoesNotExist);
413+
Err(ErrorSource::AnchorDoesNotExist.into())
363414
}
364415

365416
/// Returns global number of states created by all stateful rules (see keep_state)
@@ -419,7 +470,10 @@ mod tests {
419470
let cchars: &[i8] = unsafe { mem::transmute(cstr.as_bytes()) };
420471
assert_matches!(
421472
compare_cstr_safe("Hello", cchars),
422-
Err(ref e) if e.description() == "Not null terminated"
473+
Err(Error {
474+
source: ErrorSource::CstrNotTerminated,
475+
..
476+
})
423477
);
424478
}
425479

src/macros.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ macro_rules! ioctl_guard {
1616
($func:expr, $already_active:expr) => {
1717
if unsafe { $func } == $crate::macros::IOCTL_ERROR {
1818
let ::errno::Errno(error_code) = ::errno::errno();
19-
let io_error = ::std::io::Error::from_raw_os_error(error_code);
20-
let mut err = Err($crate::ErrorKind::IoctlError(io_error).into());
19+
let err = ::std::io::Error::from_raw_os_error(error_code);
2120
if error_code == $already_active {
22-
err = err.chain_err(|| $crate::ErrorKind::StateAlreadyActive);
21+
Err($crate::ErrorSource::StateAlreadyActive(err).into())
22+
} else {
23+
Err($crate::ErrorSource::from(err).into())
2324
}
24-
err
2525
} else {
2626
Ok(()) as $crate::Result<()>
2727
}

src/pooladdr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
conversion::{CopyTo, TryCopyTo},
1111
ffi, Interface, Ip, Result,
1212
};
13-
use std::{mem, ptr, vec::Vec};
13+
use std::{mem, ptr};
1414

1515
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1616
pub struct PoolAddr {

src/rule/gid.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9-
pub use super::uid::{Id, IdUnaryModifier};
9+
pub use super::uid::Id;
1010
use crate::{
1111
conversion::TryCopyTo,
1212
ffi::pfvar::{pf_rule_gid, PF_OP_NONE},

0 commit comments

Comments
 (0)