Skip to content

Commit c638615

Browse files
committed
clean up syscall return value handling a bit
1 parent d686dfd commit c638615

File tree

1 file changed

+39
-32
lines changed

1 file changed

+39
-32
lines changed

src/syscall.rs

+39-32
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
// Copyright (c) iliana destroyer of worlds <[email protected]>
22
// SPDX-License-Identifier: MIT
33

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-
84
use std::ffi::CStr;
95
use std::fmt::{self, Debug};
106
use std::fs::File;
@@ -23,46 +19,57 @@ const F_SEAL_EXEC: c_int = 0x0020;
2319

2420
pub(crate) fn memfd_create(name: &CStr, flags: MemfdFlags) -> Result<File, Error> {
2521
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) });
2823
#[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) })
3126
}
3227

3328
pub(crate) fn fcntl_get_seals(file: &File) -> Result<SealFlags, Error> {
3429
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
4935
}
5036

5137
pub(crate) fn fcntl_add_seals(file: &File, arg: SealFlags) -> Result<(), Error> {
5238
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) });
5540
#[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(|_| ())
5843
}
5944

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+
}
6673
}
6774
}
6875

0 commit comments

Comments
 (0)