Make process wait optional

This commit is contained in:
Caelan Sayler
2025-05-23 21:04:35 +01:00
parent dfc87a391f
commit a0cca6afbc
4 changed files with 28 additions and 12 deletions

View File

@@ -58,7 +58,7 @@ pub fn apply_package_impl(old_locator: &VelopackLocator, package: &PathBuf, run_
let process_handle = process::run_process_as_admin(&exe_path, args, work_dir, false)?; let process_handle = process::run_process_as_admin(&exe_path, args, work_dir, false)?;
info!("Waiting (up to 10 minutes) for elevated process to exit..."); info!("Waiting (up to 10 minutes) for elevated process to exit...");
let result = process::wait_for_process_to_exit_with_timeout(process_handle, Duration::from_secs(10 * 60))?; let result = process::wait_for_process_to_exit(process_handle, Some(Duration::from_secs(10 * 60)))?;
info!("Elevated process has exited ({:?}).", result); info!("Elevated process has exited ({:?}).", result);
return Ok(new_locator); return Ok(new_locator);
} }

View File

@@ -13,11 +13,11 @@ pub enum OperationWait {
pub fn operation_wait(wait: OperationWait) { pub fn operation_wait(wait: OperationWait) {
if let OperationWait::WaitPid(pid) = wait { if let OperationWait::WaitPid(pid) = wait {
if let Err(e) = process::wait_for_pid_to_exit(pid, Duration::from_secs(60)) { if let Err(e) = process::wait_for_pid_to_exit(pid, Some(Duration::from_secs(60))) {
warn!("Failed to wait for process ({}) to exit ({}). Continuing...", pid, e); warn!("Failed to wait for process ({}) to exit ({}). Continuing...", pid, e);
} }
} else if let OperationWait::WaitParent = wait { } else if let OperationWait::WaitParent = wait {
if let Err(e) = process::wait_for_parent_to_exit(Duration::from_secs(60)) { if let Err(e) = process::wait_for_parent_to_exit(Some(Duration::from_secs(60))) {
warn!("Failed to wait for parent process to exit ({}). Continuing...", e); warn!("Failed to wait for parent process to exit ({}). Continuing...", e);
} }
} else { } else {

View File

@@ -40,7 +40,7 @@ pub fn run_hook(locator: &VelopackLocator, hook_name: &str, timeout_secs: u64) -
let cmd = cmd.unwrap(); let cmd = cmd.unwrap();
match process::wait_for_process_to_exit_with_timeout(&cmd, Duration::from_secs(timeout_secs)) { match process::wait_for_process_to_exit(&cmd, Some(Duration::from_secs(timeout_secs))) {
Ok(WaitResult::NoWaitRequired) => { Ok(WaitResult::NoWaitRequired) => {
warn!("Was unable to wait for hook (it may have exited too quickly)."); warn!("Was unable to wait for hook (it may have exited too quickly).");
} }

View File

@@ -14,7 +14,7 @@ use windows::{
Security::{GetTokenInformation, TokenElevation, TOKEN_ELEVATION}, Security::{GetTokenInformation, TokenElevation, TOKEN_ELEVATION},
System::Threading::{ System::Threading::{
CreateProcessW, GetCurrentProcess, GetExitCodeProcess, GetProcessId, GetProcessTimes, OpenProcess, OpenProcessToken, CreateProcessW, GetCurrentProcess, GetExitCodeProcess, GetProcessId, GetProcessTimes, OpenProcess, OpenProcessToken,
TerminateProcess, WaitForSingleObject, CREATE_NO_WINDOW, CREATE_UNICODE_ENVIRONMENT, PROCESS_ACCESS_RIGHTS, TerminateProcess, WaitForSingleObject, CREATE_NO_WINDOW, CREATE_UNICODE_ENVIRONMENT, INFINITE, PROCESS_ACCESS_RIGHTS,
PROCESS_BASIC_INFORMATION, PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_SYNCHRONIZE, PROCESS_TERMINATE, STARTUPINFOW, PROCESS_BASIC_INFORMATION, PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_SYNCHRONIZE, PROCESS_TERMINATE, STARTUPINFOW,
STARTUPINFOW_FLAGS, STARTUPINFOW_FLAGS,
}, },
@@ -394,14 +394,30 @@ pub enum WaitResult {
NoWaitRequired, NoWaitRequired,
} }
pub fn wait_for_process_to_exit_with_timeout<T: AsRef<HANDLE>>(process: T, dur: Duration) -> IoResult<WaitResult> { impl WaitResult {
pub fn code(&self) -> Option<u32> {
match self {
WaitResult::WaitTimeout => None,
WaitResult::ExitCode(c) => Some(*c),
WaitResult::NoWaitRequired => None,
}
}
}
pub fn wait_for_process_to_exit<T: AsRef<HANDLE>>(process: T, dur: Option<Duration>) -> IoResult<WaitResult> {
let process = *process.as_ref(); let process = *process.as_ref();
if process.is_invalid() { if process.is_invalid() {
return Ok(WaitResult::NoWaitRequired); return Ok(WaitResult::NoWaitRequired);
} }
let ms = duration_to_ms(dur); let ms = if let Some(dur) = dur {
info!("Waiting {}ms for process handle to exit.", ms); let ms = duration_to_ms(dur);
info!("Waiting {}ms for process handle to exit.", ms);
ms
} else {
info!("Waiting indefinitely process handle to exit.");
INFINITE
};
unsafe { unsafe {
match WaitForSingleObject(process, ms) { match WaitForSingleObject(process, ms) {
@@ -416,13 +432,13 @@ pub fn wait_for_process_to_exit_with_timeout<T: AsRef<HANDLE>>(process: T, dur:
} }
} }
pub fn wait_for_pid_to_exit(pid: u32, dur: Duration) -> IoResult<WaitResult> { pub fn wait_for_pid_to_exit(pid: u32, dur: Option<Duration>) -> IoResult<WaitResult> {
info!("Waiting for process pid-{} to exit.", pid); info!("Waiting for process pid-{} to exit.", pid);
let handle = open_process(PROCESS_SYNCHRONIZE, false, pid)?; let handle = open_process(PROCESS_SYNCHRONIZE, false, pid)?;
wait_for_process_to_exit_with_timeout(handle, dur) wait_for_process_to_exit(handle, dur)
} }
pub fn wait_for_parent_to_exit(dur: Duration) -> IoResult<WaitResult> { pub fn wait_for_parent_to_exit(dur: Option<Duration>) -> IoResult<WaitResult> {
info!("Reading parent process information."); info!("Reading parent process information.");
let basic_info = ProcessBasicInformation; let basic_info = ProcessBasicInformation;
let my_handle = unsafe { GetCurrentProcess() }; let my_handle = unsafe { GetCurrentProcess() };
@@ -477,7 +493,7 @@ pub fn wait_for_parent_to_exit(dur: Duration) -> IoResult<WaitResult> {
} }
info!("Waiting for parent process ({}) to exit.", info.InheritedFromUniqueProcessId); info!("Waiting for parent process ({}) to exit.", info.InheritedFromUniqueProcessId);
wait_for_process_to_exit_with_timeout(parent_handle, dur) wait_for_process_to_exit(parent_handle, dur)
} }
#[test] #[test]