|
2 | 2 | // SPDX-License-Identifier: Apache-2.0 |
3 | 3 |
|
4 | 4 | use std::collections::HashMap; |
| 5 | +use std::env; |
| 6 | +use std::ffi::CString; |
5 | 7 | #[cfg(target_os = "macos")] |
6 | 8 | use std::fs::File; |
7 | 9 | #[cfg(target_os = "macos")] |
8 | | -use std::io::{self, Read, Write}; |
| 10 | +use std::io::{self, Error, ErrorKind, Read, Write}; |
| 11 | +use std::os::unix::ffi::OsStringExt; |
9 | 12 |
|
10 | 13 | use crate::commands::{ |
11 | 14 | ChangeVmCmd, ConfigCmd, CreateCmd, DeleteCmd, InspectCmd, ListCmd, StartCmd, |
12 | 15 | }; |
13 | 16 | use clap::{Parser, Subcommand}; |
| 17 | +use nix::unistd::execve; |
14 | 18 | use serde_derive::{Deserialize, Serialize}; |
15 | 19 | #[cfg(target_os = "macos")] |
16 | 20 | use text_io::read; |
@@ -169,7 +173,62 @@ enum Command { |
169 | 173 | Config(ConfigCmd), |
170 | 174 | } |
171 | 175 |
|
| 176 | +#[cfg(target_os = "macos")] |
| 177 | +fn get_brew_prefix() -> Option<String> { |
| 178 | + let output = std::process::Command::new("brew") |
| 179 | + .arg("--prefix") |
| 180 | + .stderr(std::process::Stdio::inherit()) |
| 181 | + .output() |
| 182 | + .ok()?; |
| 183 | + |
| 184 | + let exit_code = output.status.code().unwrap_or(-1); |
| 185 | + if exit_code != 0 { |
| 186 | + return None; |
| 187 | + } |
| 188 | + |
| 189 | + Some(std::str::from_utf8(&output.stdout).ok()?.trim().to_string()) |
| 190 | +} |
| 191 | + |
| 192 | +#[cfg(target_os = "macos")] |
| 193 | +fn reexec() -> Result<(), Error> { |
| 194 | + let args: Vec<CString> = env::args_os() |
| 195 | + .map(|arg| CString::new(arg.into_vec()).unwrap()) |
| 196 | + .collect(); |
| 197 | + |
| 198 | + let mut envs: Vec<CString> = env::vars_os() |
| 199 | + .map(|(key, value)| { |
| 200 | + CString::new(format!( |
| 201 | + "{}={}", |
| 202 | + key.into_string().unwrap(), |
| 203 | + value.into_string().unwrap() |
| 204 | + )) |
| 205 | + .unwrap() |
| 206 | + }) |
| 207 | + .collect(); |
| 208 | + let brew_prefix = get_brew_prefix().ok_or(ErrorKind::NotFound)?; |
| 209 | + envs.push(CString::new(format!( |
| 210 | + "DYLD_LIBRARY_PATH={brew_prefix}/lib" |
| 211 | + ))?); |
| 212 | + |
| 213 | + // Use execve to replace the current process. This function only returns |
| 214 | + // if an error occurs. |
| 215 | + match execve(&args[0], &args, &envs) { |
| 216 | + Ok(_) => Ok(()), |
| 217 | + Err(e) => { |
| 218 | + eprintln!("Error re-executing krunvm: {}", e); |
| 219 | + std::process::exit(-1); |
| 220 | + } |
| 221 | + } |
| 222 | +} |
| 223 | + |
172 | 224 | fn main() { |
| 225 | + #[cfg(target_os = "macos")] |
| 226 | + { |
| 227 | + if env::var("DYLD_LIBRARY_PATH").is_err() { |
| 228 | + _ = reexec(); |
| 229 | + } |
| 230 | + } |
| 231 | + |
173 | 232 | let mut cfg: KrunvmConfig = confy::load(APP_NAME).unwrap(); |
174 | 233 | let cli_args = Cli::parse(); |
175 | 234 |
|
|
0 commit comments