1
1
// Copyright (c) iliana destroyer of worlds <[email protected] >
2
2
// SPDX-License-Identifier: MIT
3
3
4
- // syscall returns a c_long but memfd_create(2) and fcntl(2) are documented as returning c_int. The
5
- // values are truncated here instead of using TryFrom.
6
- #![ allow( clippy:: cast_possible_truncation) ]
7
-
8
4
use std:: ffi:: CStr ;
9
5
use std:: fmt:: { self , Debug } ;
10
6
use std:: fs:: File ;
@@ -23,46 +19,57 @@ const F_SEAL_EXEC: c_int = 0x0020;
23
19
24
20
pub ( crate ) fn memfd_create ( name : & CStr , flags : MemfdFlags ) -> Result < File , Error > {
25
21
let name: * const c_char = name. as_ptr ( ) ;
26
- let retval = unsafe { syscall ( SYS_memfd_create , name, flags. 0 ) } ;
27
- let result = check_syscall ( retval) ;
22
+ let result = SyscallResult :: new ( unsafe { syscall ( SYS_memfd_create , name, flags. 0 ) } ) ;
28
23
#[ cfg( feature = "log" ) ]
29
- log:: trace!( "memfd_create({name:?}, {flags:?}) = {retval }" ) ;
30
- result. map ( |( ) | unsafe { File :: from_raw_fd ( retval as c_int ) } )
24
+ log:: trace!( "memfd_create({name:?}, {flags:?}) = {result:? }" ) ;
25
+ result. 0 . map ( |value | unsafe { File :: from_raw_fd ( value ) } )
31
26
}
32
27
33
28
pub ( crate ) fn fcntl_get_seals ( file : & File ) -> Result < SealFlags , Error > {
34
29
let fd: c_int = file. as_raw_fd ( ) ;
35
- let retval = unsafe { syscall ( SYS_fcntl , fd, F_GET_SEALS ) } ;
36
- match check_syscall ( retval) {
37
- Ok ( ( ) ) => {
38
- let retval = SealFlags ( retval as c_int ) ;
39
- #[ cfg( feature = "log" ) ]
40
- log:: trace!( "fcntl({fd}, F_GET_SEALS) = {retval:?}" ) ;
41
- Ok ( retval)
42
- }
43
- Err ( err) => {
44
- #[ cfg( feature = "log" ) ]
45
- log:: trace!( "fcntl({fd}, F_GET_SEALS) = {retval}" ) ;
46
- Err ( err)
47
- }
48
- }
30
+ let result = SyscallResult :: new ( unsafe { syscall ( SYS_fcntl , fd, F_GET_SEALS ) } ) ;
31
+ let result = SyscallResult ( result. 0 . map ( SealFlags ) ) ;
32
+ #[ cfg( feature = "log" ) ]
33
+ log:: trace!( "fcntl({fd}, F_GET_SEALS) = {result:?}" ) ;
34
+ result. 0
49
35
}
50
36
51
37
pub ( crate ) fn fcntl_add_seals ( file : & File , arg : SealFlags ) -> Result < ( ) , Error > {
52
38
let fd: c_int = file. as_raw_fd ( ) ;
53
- let retval = unsafe { syscall ( SYS_fcntl , fd, F_ADD_SEALS , arg. 0 ) } ;
54
- let result = check_syscall ( retval) ;
39
+ let result = SyscallResult :: new ( unsafe { syscall ( SYS_fcntl , fd, F_ADD_SEALS , arg. 0 ) } ) ;
55
40
#[ cfg( feature = "log" ) ]
56
- log:: trace!( "fcntl({fd}, F_ADD_SEALS, {arg:?}) = {retval }" ) ;
57
- result
41
+ log:: trace!( "fcntl({fd}, F_ADD_SEALS, {arg:?}) = {result:? }" ) ;
42
+ result. 0 . map ( |_| ( ) )
58
43
}
59
44
60
- #[ inline]
61
- fn check_syscall ( retval : c_long ) -> Result < ( ) , Error > {
62
- if retval < 0 {
63
- Err ( Error :: last_os_error ( ) )
64
- } else {
65
- Ok ( ( ) )
45
+ #[ repr( transparent) ]
46
+ struct SyscallResult < T > ( Result < T , Error > ) ;
47
+
48
+ impl SyscallResult < c_int > {
49
+ #[ inline]
50
+ fn new ( value : c_long ) -> Self {
51
+ // The `syscall` function returns c_long regardless of the actual return value of the
52
+ // syscall. In the case of memfd_create(2) and fcntl(2), both syscalls return c_int.
53
+ // Truncation of the return value is correct behavior on Linux; see:
54
+ // https://github.com/rust-lang/rust/blob/56e35a5dbb37898433a43133dff0398f46d577b8/library/std/src/sys/pal/unix/weak.rs#L160-L184
55
+ #![ allow( clippy:: cast_possible_truncation) ]
56
+ let value = value as c_int ;
57
+
58
+ // memfd_create(2) and fcntl(2) both return -1 on error.
59
+ if value == -1 {
60
+ Self ( Err ( Error :: last_os_error ( ) ) )
61
+ } else {
62
+ Self ( Ok ( value) )
63
+ }
64
+ }
65
+ }
66
+
67
+ impl < T : Debug > Debug for SyscallResult < T > {
68
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
69
+ match & self . 0 {
70
+ Ok ( value) => write ! ( f, "{value:?}" ) ,
71
+ Err ( err) => write ! ( f, "-1 {err}" ) ,
72
+ }
66
73
}
67
74
}
68
75
0 commit comments