1 // Copyright 2021, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use command_fds::{CommandFdExt, FdMapping};
16 use std::fs::{read_dir, read_link, File};
17 use std::io::stdin;
18 use std::os::fd::AsFd;
19 use std::os::unix::process::CommandExt;
20 use std::process::Command;
21 use std::thread::sleep;
22 use std::time::Duration;
23 
24 /// Print out a list of all open file descriptors.
list_fds()25 fn list_fds() {
26     let dir = read_dir("/proc/self/fd").unwrap();
27     for entry in dir {
28         let entry = entry.unwrap();
29         let target = read_link(entry.path()).unwrap();
30         println!("{:?} {:?}", entry, target);
31     }
32 }
33 
main()34 fn main() {
35     list_fds();
36 
37     // Open a file.
38     let file = File::open("Cargo.toml").unwrap();
39     println!("File: {:?}", file);
40     list_fds();
41 
42     // Prepare to run `ls -l /proc/self/fd` with some FDs mapped.
43     let mut command = Command::new("ls");
44     let stdin = stdin().as_fd().try_clone_to_owned().unwrap();
45     command.arg("-l").arg("/proc/self/fd");
46     command
47         .fd_mappings(vec![
48             // Map `file` as FD 3 in the child process.
49             FdMapping {
50                 parent_fd: file.into(),
51                 child_fd: 3,
52             },
53             // Map this process's stdin as FD 5 in the child process.
54             FdMapping {
55                 parent_fd: stdin,
56                 child_fd: 5,
57             },
58         ])
59         .unwrap();
60     unsafe {
61         command.pre_exec(move || {
62             println!("pre_exec");
63             list_fds();
64             Ok(())
65         });
66     }
67 
68     // Spawn the child process.
69     println!("Spawning command");
70     let mut child = command.spawn().unwrap();
71     sleep(Duration::from_millis(100));
72     println!("Spawned");
73     list_fds();
74 
75     println!("Waiting for command");
76     println!("{:?}", child.wait().unwrap());
77 }
78