use color_eyre::eyre::bail;
#[cfg(target_os = "windows")]
pub fn is_admin() -> bool {
use std::mem;
use windows::Win32::Foundation::{CloseHandle, HANDLE};
use windows::Win32::Security::{
GetTokenInformation, TOKEN_ELEVATION, TOKEN_QUERY, TokenElevation,
};
use windows::Win32::System::Threading::{GetCurrentProcess, OpenProcessToken};
unsafe {
let mut token: HANDLE = HANDLE::default();
if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token).is_err() {
return false;
}
let mut elevation = TOKEN_ELEVATION::default();
let mut size = mem::size_of::<TOKEN_ELEVATION>() as u32;
let result = GetTokenInformation(
token,
TokenElevation,
Some(&mut elevation as *mut _ as *mut _),
size,
&mut size,
);
let _ = CloseHandle(token);
result.is_ok() && elevation.TokenIsElevated != 0
}
}
#[cfg(not(target_os = "windows"))]
pub fn is_admin() -> bool {
false
}
#[cfg(target_os = "windows")]
pub fn restart_as_admin() -> color_eyre::Result<()> {
use itertools::Itertools;
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use windows::Win32::UI::Shell::ShellExecuteW;
use windows::Win32::UI::WindowsAndMessaging::SW_SHOW;
use windows::core::PCWSTR;
let exe_path: Vec<u16> = std::env::current_exe()?
.as_os_str()
.encode_wide()
.chain(Some(0))
.collect();
let args = std::env::args()
.skip(1)
.map(|arg| format!("\"{}\"", arg.replace('\"', "\"\"")))
.join(" ");
let args: Vec<u16> = OsStr::new(&args).encode_wide().chain(Some(0)).collect();
let cwd: Vec<u16> = std::env::current_dir()?
.as_os_str()
.encode_wide()
.chain(Some(0))
.collect();
unsafe {
let instance = ShellExecuteW(
None,
windows::core::w!("runas"),
PCWSTR(exe_path.as_ptr()),
PCWSTR(args.as_ptr()),
PCWSTR(cwd.as_ptr()),
SW_SHOW,
);
if instance.0 as usize > 32 {
std::process::exit(0);
} else {
let err = std::io::Error::last_os_error();
bail!("Failed to restart as admin (UAC denied or Error): {}", err);
}
}
}
#[cfg(not(target_os = "windows"))]
pub fn restart_as_admin() -> color_eyre::Result<()> {
bail!("Running as admin is not supported on this platform")
}
#[allow(unused_variables)]
pub fn try_restart_as_admin(run_as_admin: bool) -> color_eyre::Result<()> {
#[cfg(target_os = "windows")]
if run_as_admin && !is_admin() {
tracing::info!("Restarting as administrator...");
return restart_as_admin();
}
Ok(())
}