1use linux_api::close_range::CloseRangeFlags;
2use linux_api::errno::Errno;
3use linux_api::fcntl::DescriptorFlags;
45use crate::host::descriptor::descriptor_table;
6use crate::host::syscall::handler::{SyscallContext, SyscallHandler};
7use crate::utility::callback_queue::CallbackQueue;
89impl SyscallHandler {
10log_syscall!(
11 close_range,
12/* rv */ std::ffi::c_int,
13/* first */ std::ffi::c_uint,
14/* last */ std::ffi::c_uint,
15/* flags */ CloseRangeFlags,
16 );
17pub fn close_range(
18 ctx: &mut SyscallContext,
19 first: std::ffi::c_uint,
20 last: std::ffi::c_uint,
21 flags: std::ffi::c_uint,
22 ) -> Result<(), Errno> {
23// close_range(2):
24 // > EINVAL: [...], or first is greater than last.
25if first > last {
26return Err(Errno::EINVAL);
27 }
2829// if the start of the range is larger than the max possible fd, then do nothing
30if first > descriptor_table::FD_MAX {
31return Ok(());
32 }
3334// restrict the end of the range to the max possible fd
35let last = std::cmp::min(last, descriptor_table::FD_MAX);
3637// we ensured above that first and last are within the allowed fd range
38let first = first.try_into().unwrap();
39let last = last.try_into().unwrap();
4041let range = first..=last;
4243let Some(flags) = CloseRangeFlags::from_bits(flags) else {
44log::debug!("Invalid close_range flags: {flags}");
45return Err(Errno::EINVAL);
46 };
4748if flags.contains(CloseRangeFlags::CLOSE_RANGE_UNSHARE) {
49log::debug!("The CLOSE_RANGE_UNSHARE flag is not implemented");
50return Err(Errno::EINVAL);
51 }
5253let mut desc_table = ctx.objs.thread.descriptor_table_borrow_mut(ctx.objs.host);
5455if flags.contains(CloseRangeFlags::CLOSE_RANGE_CLOEXEC) {
56// close_range(2):
57 // > CLOSE_RANGE_CLOEXEC: Set the close-on-exec flag on the specified file descriptors,
58 // > rather than immediately closing them.
5960 // set the CLOEXEC flag on all descriptors in the range
61for (fd, desc) in desc_table.iter_mut() {
62if range.contains(fd) {
63 desc.set_flags(desc.flags() | DescriptorFlags::FD_CLOEXEC);
64 }
65 }
66 } else {
67// remove all descriptors in the range
68let descriptors = desc_table.remove_range(range);
6970// close the removed descriptors
71CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
72for desc in descriptors {
73// close_range(2):
74 // > Errors closing a given file descriptor are currently ignored.
75let _ = desc.close(ctx.objs.host, cb_queue);
76 }
77 });
78 }
7980Ok(())
81 }
82}