| 120 | } |
| 121 | |
| 122 | fn create_pty() -> io::Result<(File, File, PathBuf)> { |
| 123 | // Try to use /dev/pts/ptmx first then fall back to /dev/ptmx |
| 124 | // This is done to try and use the devpts filesystem that |
| 125 | // could be available for use in the process's namespace first. |
| 126 | // Ideally these are all the same file though but different |
| 127 | // kernels could have things setup differently. |
| 128 | // See https://www.kernel.org/doc/Documentation/filesystems/devpts.txt |
| 129 | // for further details. |
| 130 | |
| 131 | let custom_flags = libc::O_NONBLOCK; |
| 132 | let main = match OpenOptions::new() |
| 133 | .read(true) |
| 134 | .write(true) |
| 135 | .custom_flags(custom_flags) |
| 136 | .open("/dev/pts/ptmx") |
| 137 | { |
| 138 | Ok(f) => f, |
| 139 | _ => OpenOptions::new() |
| 140 | .read(true) |
| 141 | .write(true) |
| 142 | .custom_flags(custom_flags) |
| 143 | .open("/dev/ptmx")?, |
| 144 | }; |
| 145 | let mut unlock: libc::c_ulong = 0; |
| 146 | // SAFETY: FFI call into libc, trivially safe |
| 147 | unsafe { libc::ioctl(main.as_raw_fd(), TIOCSPTLCK as _, &mut unlock) }; |
| 148 | |
| 149 | // SAFETY: FFI call into libc, trivially safe |
| 150 | let sub_fd = unsafe { |
| 151 | libc::ioctl( |
| 152 | main.as_raw_fd(), |
| 153 | TIOCGPTPEER as _, |
| 154 | libc::O_NOCTTY | libc::O_RDWR, |
| 155 | ) |
| 156 | }; |
| 157 | if sub_fd == -1 { |
| 158 | return vmm_sys_util::errno::errno_result().map_err(|e| e.into()); |
| 159 | } |
| 160 | |
| 161 | let proc_path = PathBuf::from(format!("/proc/self/fd/{sub_fd}")); |
| 162 | let path = read_link(proc_path)?; |
| 163 | |
| 164 | // SAFETY: sub_fd is checked to be valid before being wrapped in File |
| 165 | Ok((main, unsafe { File::from_raw_fd(sub_fd) }, path)) |
| 166 | } |
| 167 | |
| 168 | fn dup_stdout() -> vmm_sys_util::errno::Result<File> { |
| 169 | // SAFETY: FFI call to dup. Trivially safe. |