5959
6060#![ deny( rust_2018_idioms) ]  
6161
62- #[ macro_use]  
63- pub  extern  crate  error_chain; 
64- 
6562use  std:: { 
6663    ffi:: CStr , 
64+     fmt:: Display , 
6765    fs:: File , 
6866    mem, 
6967    os:: unix:: io:: { AsRawFd ,  RawFd } , 
7068} ; 
69+ use  thiserror:: Error ; 
7170
7271pub  use  ipnetwork; 
7372
@@ -92,40 +91,87 @@ pub use crate::ruleset::*;
9291mod  transaction; 
9392pub  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. 
125171macro_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 
150196fn  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
0 commit comments