diff options
Diffstat (limited to 'src/windows_util.rs')
| -rw-r--r-- | src/windows_util.rs | 105 |
1 files changed, 81 insertions, 24 deletions
diff --git a/src/windows_util.rs b/src/windows_util.rs index 348ea91..3b1339e 100644 --- a/src/windows_util.rs +++ b/src/windows_util.rs @@ -1,5 +1,8 @@ use windows::{ - core::HSTRING, + core::{ + HSTRING, + PWSTR, + }, Win32::{ Foundation, System::Services, @@ -10,43 +13,26 @@ lazy_static::lazy_static! { static ref PSQL_REGEX: regex::Regex = regex::Regex::new(r#"^(?:postgresql|psql|postgres)-.*([\d\.]*)"#).unwrap(); } -pub unsafe fn ensure_postgres_started() -> windows::core::Result<()> { +pub unsafe fn ensure_postgres_started() -> windows::core::Result<bool> { let sc_manager = Services::OpenSCManagerW( None, None, (Foundation::GENERIC_READ | Foundation::GENERIC_WRITE).0, )?; - let services = list_services(sc_manager)?; - - let mut psql_services = - services.into_iter().filter(|status| PSQL_REGEX.is_match(&status.name)).collect::<Vec<_>>(); - - match psql_services.len() { - 1 => {}, - - 0 => { - log::warn!("unable to identify an installed postgres service"); - }, - - other => { - log::warn!("unable to identify postgres service: {other} potential matches found"); - return Ok(()); - }, - } - - let svc = psql_services.remove(0); - log::debug!("identified postgres service: {}", svc.name); + let Some(svc) = get_psql_service(sc_manager)? else { + return Ok(false); + }; match svc.status.dwCurrentState { Services::SERVICE_RUNNING => { log::info!("postgres was already running, done"); - return Ok(()); + return Ok(false); }, Services::SERVICE_START_PENDING => { log::info!("postgres was already in startup, done"); - return Ok(()); + return Ok(false); }, _ => { @@ -64,9 +50,80 @@ pub unsafe fn ensure_postgres_started() -> windows::core::Result<()> { Services::CloseServiceHandle(service)?; Services::CloseServiceHandle(sc_manager)?; + Ok(true) +} + +pub unsafe fn shutdown_postgres() -> windows::core::Result<()> { + let sc_manager = Services::OpenSCManagerW( + None, + None, + (Foundation::GENERIC_READ | Foundation::GENERIC_WRITE).0, + )?; + + let Some(svc) = get_psql_service(sc_manager)? else { + log::warn!("wasn't able to find postgres service"); + return Ok(()); + }; + + if svc.status.dwCurrentState != Services::SERVICE_RUNNING { + log::warn!("postgres wasn't in running state, not attempting to shut it down"); + return Ok(()); + } + + let service = + Services::OpenServiceW(sc_manager, &HSTRING::from(&svc.name), Services::SERVICE_STOP)?; + + let mut params = Services::SERVICE_CONTROL_STATUS_REASON_PARAMSW { + dwReason: Services::SERVICE_STOP_REASON_FLAG_PLANNED + | Services::SERVICE_STOP_REASON_MAJOR_NONE + | Services::SERVICE_STOP_REASON_MINOR_NONE, + pszComment: PWSTR::null(), + ServiceStatus: Services::SERVICE_STATUS_PROCESS::default(), + }; + + Services::ControlServiceExW( + service, + Services::SERVICE_CONTROL_STOP, + Services::SERVICE_CONTROL_STATUS_REASON_INFO, + &mut params as *mut _ as _, + )?; + + log::info!("stopped postgres service"); + + Services::CloseServiceHandle(service)?; + Services::CloseServiceHandle(sc_manager)?; + Ok(()) } +pub unsafe fn get_psql_service( + sc_manager: Services::SC_HANDLE, +) -> windows::core::Result<Option<ServiceStatus>> { + let services = list_services(sc_manager)?; + + let mut psql_services = + services.into_iter().filter(|status| PSQL_REGEX.is_match(&status.name)).collect::<Vec<_>>(); + + match psql_services.len() { + 1 => {}, + + 0 => { + log::warn!("unable to identify an installed postgres service"); + return Ok(None); + }, + + other => { + log::warn!("unable to identify postgres service: {other} potential matches found"); + return Ok(None); + }, + } + + let svc = psql_services.remove(0); + log::debug!("identified postgres service: {}", svc.name); + + Ok(Some(svc)) +} + const RESULT_SIZE: usize = size_of::<Services::ENUM_SERVICE_STATUS_PROCESSW>(); pub struct ServiceStatus { |
