@@ -209,3 +209,89 @@ pub(crate) enum TestRulesetError {
209209 #[ error( transparent) ]
210210 File ( #[ from] std:: io:: Error ) ,
211211}
212+
213+ /// Get the underlying errno value.
214+ ///
215+ /// This helper is useful for FFI to easily translate a Landlock error into an
216+ /// errno value.
217+ #[ derive( Debug , PartialEq , Eq ) ]
218+ pub struct Errno ( libc:: c_int ) ;
219+
220+ impl Errno {
221+ pub fn new ( value : libc:: c_int ) -> Self {
222+ Self ( value)
223+ }
224+ }
225+
226+ impl < T > From < T > for Errno
227+ where
228+ T : std:: error:: Error ,
229+ {
230+ fn from ( error : T ) -> Self {
231+ let default = libc:: EINVAL ;
232+ if let Some ( e) = error. source ( ) {
233+ if let Some ( e) = e. downcast_ref :: < std:: io:: Error > ( ) {
234+ return Errno ( e. raw_os_error ( ) . unwrap_or ( default) ) ;
235+ }
236+ }
237+ Errno ( default)
238+ }
239+ }
240+
241+ impl AsRef < libc:: c_int > for Errno {
242+ fn as_ref ( & self ) -> & libc:: c_int {
243+ & self . 0
244+ }
245+ }
246+
247+ #[ cfg( test) ]
248+ fn _test_ruleset_errno ( expected_errno : libc:: c_int ) {
249+ use std:: io:: Error ;
250+
251+ let handle_access_err = RulesetError :: HandleAccesses ( HandleAccessesError :: Fs (
252+ HandleAccessError :: Compat ( CompatError :: Access ( AccessError :: Empty ) ) ,
253+ ) ) ;
254+ assert_eq ! ( Errno :: from( handle_access_err) . 0 , libc:: EINVAL ) ;
255+
256+ let create_ruleset_err = RulesetError :: CreateRuleset ( CreateRulesetError :: CreateRulesetCall {
257+ source : Error :: from_raw_os_error ( expected_errno) ,
258+ } ) ;
259+ assert_eq ! ( Errno :: from( create_ruleset_err) . 0 , expected_errno) ;
260+
261+ let add_rules_fs_err = RulesetError :: AddRules ( AddRulesError :: Fs ( AddRuleError :: AddRuleCall {
262+ source : Error :: from_raw_os_error ( expected_errno) ,
263+ } ) ) ;
264+ assert_eq ! ( Errno :: from( add_rules_fs_err) . 0 , expected_errno) ;
265+
266+ let add_rules_net_err = RulesetError :: AddRules ( AddRulesError :: Net ( AddRuleError :: AddRuleCall {
267+ source : Error :: from_raw_os_error ( expected_errno) ,
268+ } ) ) ;
269+ assert_eq ! ( Errno :: from( add_rules_net_err) . 0 , expected_errno) ;
270+
271+ let add_rules_other_err =
272+ RulesetError :: AddRules ( AddRulesError :: Fs ( AddRuleError :: UnhandledAccess {
273+ access : AccessFs :: Execute . into ( ) ,
274+ incompatible : BitFlags :: < AccessFs > :: EMPTY ,
275+ } ) ) ;
276+ assert_eq ! ( Errno :: from( add_rules_other_err) . 0 , libc:: EINVAL ) ;
277+
278+ let restrict_self_err = RulesetError :: RestrictSelf ( RestrictSelfError :: RestrictSelfCall {
279+ source : Error :: from_raw_os_error ( expected_errno) ,
280+ } ) ;
281+ assert_eq ! ( Errno :: from( restrict_self_err) . 0 , expected_errno) ;
282+
283+ let set_no_new_privs_err = RulesetError :: RestrictSelf ( RestrictSelfError :: SetNoNewPrivsCall {
284+ source : Error :: from_raw_os_error ( expected_errno) ,
285+ } ) ;
286+ assert_eq ! ( Errno :: from( set_no_new_privs_err) . 0 , expected_errno) ;
287+
288+ let create_ruleset_missing_err =
289+ RulesetError :: CreateRuleset ( CreateRulesetError :: MissingHandledAccess ) ;
290+ assert_eq ! ( Errno :: from( create_ruleset_missing_err) . 0 , libc:: EINVAL ) ;
291+ }
292+
293+ #[ test]
294+ fn test_ruleset_errno ( ) {
295+ _test_ruleset_errno ( libc:: EACCES ) ;
296+ _test_ruleset_errno ( libc:: EIO ) ;
297+ }
0 commit comments