1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
use super::*;
use crate::syscalls::*;
/// ### `fd_close()`
/// Close an open file descriptor
/// For sockets this will flush the data before the socket is closed
/// Inputs:
/// - `Fd fd`
/// A file descriptor mapping to an open file to close
/// Errors:
/// - `Errno::Isdir`
/// If `fd` is a directory
/// - `Errno::Badf`
/// If `fd` is invalid or not open
#[instrument(level = "trace", skip_all, fields(pid = ctx.data().process.pid().raw(), %fd), ret)]
pub fn fd_close(mut ctx: FunctionEnvMut<'_, WasiEnv>, fd: WasiFd) -> Result<Errno, WasiError> {
wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?);
// HACK: As a special case, we don't want to close fd 3 because it can break
// some programs...
// - On Wasix, we have some default fd, 0:stdin, 1:stdout, 2:stderr, 3:root
// - On Posix, we have some default fd: 0:stdin, 1:stdout, 2:stderr
// - A POSIX program might want to closed all open fd (e.g. when Python
// spawns subprocesses), so it blindly does fd_close() for fd=3..255
// - Wasix doesn't work well when 3:root is closed, because it's the root
if fd == 3 {
tracing::debug!("Skipping fd_close(3)");
return Ok(Errno::Success);
}
let env = ctx.data();
let (_, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) };
wasi_try_ok!(state.fs.close_fd(fd));
#[cfg(feature = "journal")]
if env.enable_journal {
JournalEffector::save_fd_close(&mut ctx, fd).map_err(|err| {
tracing::error!("failed to save close descriptor event - {}", err);
WasiError::Exit(ExitCode::from(Errno::Fault))
})?;
}
Ok(Errno::Success)
}