Prepare, configure, and manage Firecracker microVMs in seconds!
virtualization linux microvm firecracker
at main 119 lines 3.3 kB view raw
1use anyhow::{anyhow, Context, Error, Result}; 2use owo_colors::OwoColorize; 3use std::{ 4 process::{Command, Output, Stdio}, 5 thread, 6}; 7 8pub fn has_sudo() -> bool { 9 Command::new("sudo") 10 .arg("-h") 11 .output() 12 .map(|output| output.status.success()) 13 .unwrap_or(false) 14} 15 16pub fn is_root() -> bool { 17 unsafe { libc::getuid() == 0 } 18} 19 20pub fn run_command(command: &str, args: &[&str], use_sudo: bool) -> Result<Output> { 21 let mut cmd = if use_sudo { 22 if !has_sudo() && !is_root() { 23 return Err(anyhow!( 24 "sudo is required for command '{}', but not available", 25 command 26 )); 27 } 28 let mut c = Command::new("sudo"); 29 c.arg(command); 30 31 match is_root() { 32 true => Command::new(command), 33 false => c, 34 } 35 } else { 36 Command::new(command) 37 }; 38 39 let output = cmd 40 .args(args) 41 .stdin(Stdio::inherit()) 42 .stderr(Stdio::piped()) 43 .output() 44 .with_context(|| format!("Failed to execute {}", command))?; 45 46 if !output.status.success() { 47 let stderr = String::from_utf8_lossy(&output.stderr); 48 return Err(anyhow!("Command {} failed: {}", command, stderr)); 49 } 50 Ok(output) 51} 52 53pub fn run_command_in_background(command: &str, args: &[&str], use_sudo: bool) -> Result<u32> { 54 let mut cmd = if use_sudo { 55 if !has_sudo() && !is_root() { 56 return Err(anyhow!( 57 "sudo is required for command '{}', but not available", 58 command 59 )); 60 } 61 62 let status = Command::new("sudo") 63 .arg("-v") 64 .stdin(Stdio::inherit()) 65 .stdout(Stdio::inherit()) 66 .stderr(Stdio::inherit()) 67 .status() 68 .context("failed to run 'sudo -v' for credential validation")?; 69 70 if !status.success() { 71 return Err(anyhow!("'sudo -v' failed (wrong password or sudo policy)")); 72 } 73 74 let mut c = Command::new("sudo"); 75 c.arg(command); 76 77 match is_root() { 78 true => Command::new(command), 79 false => c, 80 } 81 } else { 82 Command::new(command) 83 }; 84 85 let command_owned = command.to_string(); 86 let args_owned: Vec<String> = args.iter().map(|s| s.to_string()).collect(); 87 88 let (tx, rx) = std::sync::mpsc::channel::<u32>(); 89 90 thread::spawn(move || { 91 let mut child = cmd 92 .args(&args_owned) 93 .stdin(Stdio::null()) 94 .stdout(Stdio::null()) 95 .stderr(Stdio::null()) 96 .spawn() 97 .with_context(|| format!("Failed to execute {}", command_owned))?; 98 99 let pid = child.id(); 100 tx.send(pid) 101 .with_context(|| format!("Failed to send PID for command {}", command_owned))?; 102 println!( 103 "[+] Started command {} with PID {}", 104 command_owned.bright_cyan(), 105 pid.bright_cyan() 106 ); 107 108 child 109 .wait() 110 .with_context(|| format!("Failed to wait for command {}", command_owned))?; 111 Ok::<(), Error>(()) 112 }); 113 114 let pid = rx 115 .recv() 116 .with_context(|| format!("Failed to receive PID for command {}", command))?; 117 118 Ok(pid) 119}