command_close/
command-close.rs

1use std::fs;
2use std::os::unix::prelude::*;
3use std::process::Command;
4
5fn unset_cloexec(fd: RawFd) {
6    let flags = unsafe { libc::fcntl(fd, libc::F_GETFD) };
7    assert!(flags >= 0);
8
9    if flags & libc::FD_CLOEXEC != 0 {
10        assert_eq!(
11            unsafe { libc::fcntl(fd, libc::F_SETFD, flags & !libc::FD_CLOEXEC) },
12            0
13        );
14    }
15}
16
17fn main() {
18    // Open three files (really, directories), and unset the close-on-exec flag on all three
19    let f1 = fs::File::open("/").unwrap();
20    let f2 = fs::File::open("/").unwrap();
21    let f3 = fs::File::open("/").unwrap();
22    unset_cloexec(f1.as_raw_fd());
23    unset_cloexec(f2.as_raw_fd());
24    unset_cloexec(f3.as_raw_fd());
25
26    let mut keep_fds = [f1.as_raw_fd(), f3.as_raw_fd()];
27    // ALWAYS sort the list of file descriptors if possible!
28    keep_fds.sort_unstable();
29
30    let mut cmd = Command::new("true");
31
32    unsafe {
33        cmd.pre_exec(move || {
34            // On macOS/iOS, just set them as close-on-exec
35            // Some sources indicate libdispatch may crash if the file descriptors are *actually*
36            // closed
37
38            #[cfg(any(target_os = "macos", target_os = "ios"))]
39            close_fds::set_fds_cloexec(3, &keep_fds);
40            #[cfg(not(any(target_os = "macos", target_os = "ios")))]
41            close_fds::close_open_fds(3, &keep_fds);
42
43            Ok(())
44        });
45    }
46
47    cmd.status().unwrap();
48}